Compare commits

...

69 Commits

Author SHA1 Message Date
330c132e3b Removed alternate current
All checks were successful
Build and Publish / Build and Publish Discord Bot (push) Successful in 1m11s
Build and Publish / Build and Publish Minecraft Mod (push) Successful in 2m22s
2023-11-17 19:16:12 +01:00
492034865b removed world border
Some checks failed
Build and Publish / Build and Publish Discord Bot (push) Failing after 3s
Build and Publish / Build and Publish Minecraft Mod (push) Successful in 1m33s
2023-10-03 14:47:52 +02:00
f2be21ef89 refresh
Some checks failed
Build and Publish / Build and Publish Discord Bot (push) Failing after 3s
Build and Publish / Build and Publish Minecraft Mod (push) Successful in 1m49s
2023-10-03 14:46:23 +02:00
e08dc0ef17 removed yawp
Some checks failed
Build and Publish / Build and Publish Discord Bot (push) Failing after 3s
Build and Publish / Build and Publish Minecraft Mod (push) Successful in 1m47s
2023-10-03 14:45:51 +02:00
2762f6e29f removed anti logout
Some checks failed
Build and Publish / Build and Publish Discord Bot (push) Failing after 3s
Build and Publish / Build and Publish Minecraft Mod (push) Successful in 1m52s
2023-10-03 14:43:40 +02:00
1612334e00 refresh packwiz
Some checks failed
Build and Publish / Build and Publish Discord Bot (push) Failing after 3s
Build and Publish / Build and Publish Minecraft Mod (push) Successful in 2m0s
2023-10-03 14:14:26 +02:00
f3075be1cf removed plasmo voice
Some checks failed
Build and Publish / Build and Publish Discord Bot (push) Failing after 3s
Build and Publish / Build and Publish Minecraft Mod (push) Successful in 1m40s
2023-10-03 14:13:49 +02:00
83adf33910 removed holograms
Some checks failed
Build and Publish / Build and Publish Discord Bot (push) Failing after 3s
Build and Publish / Build and Publish Minecraft Mod (push) Successful in 1m49s
2023-10-03 14:11:07 +02:00
853bf3141f Updated to 1.20.2
Some checks failed
Build and Publish / Build and Publish Discord Bot (push) Failing after 27s
Build and Publish / Build and Publish Minecraft Mod (push) Successful in 2m6s
2023-10-03 14:07:50 +02:00
e99ca2f302 revert b84ae5e2c1
Some checks failed
Build and Publish / Build and Publish Discord Bot (push) Failing after 0s
Build and Publish / Build and Publish Minecraft Mod (push) Failing after 0s
revert Updated modpack to 1.20.2
2023-10-01 10:55:37 +02:00
9a8c0599ed revert 9467119249
Some checks failed
Build and Publish / Build and Publish Discord Bot (push) Failing after 0s
Build and Publish / Build and Publish Minecraft Mod (push) Failing after 0s
revert Removed hologram
2023-10-01 10:55:21 +02:00
9467119249 Removed hologram
Some checks failed
Build and Publish / Build and Publish Discord Bot (push) Failing after 0s
Build and Publish / Build and Publish Minecraft Mod (push) Failing after 0s
2023-10-01 10:47:17 +02:00
b84ae5e2c1 Updated modpack to 1.20.2
Some checks failed
Build and Publish / Build and Publish Discord Bot (push) Failing after 0s
Build and Publish / Build and Publish Minecraft Mod (push) Failing after 0s
2023-10-01 09:36:34 +02:00
7cb5b563d7 Added anticombatlog
All checks were successful
Build and Publish / Build and Publish Discord Bot (push) Successful in 49s
Build and Publish / Build and Publish Minecraft Mod (push) Successful in 2m41s
2023-09-05 16:25:26 +02:00
9e60fa8c37 Add world border fix
All checks were successful
Build and Publish / Build and Publish Discord Bot (push) Successful in 12s
Build and Publish / Build and Publish Minecraft Mod (push) Successful in 1m50s
2023-08-27 20:54:40 +02:00
5914242316 Added slime mod
All checks were successful
Build and Publish / Build and Publish Discord Bot (push) Successful in 46s
Build and Publish / Build and Publish Minecraft Mod (push) Successful in 1m59s
2023-08-22 16:58:14 +02:00
18446f1dea added link
All checks were successful
Build and Publish / Build and Publish Discord Bot (push) Successful in 26s
Build and Publish / Build and Publish Minecraft Mod (push) Successful in 1m42s
2023-08-20 16:38:38 +02:00
d81879cec2 Added modpack
All checks were successful
Build and Publish / Build and Publish Discord Bot (push) Successful in 12s
Build and Publish / Build and Publish Minecraft Mod (push) Successful in 1m45s
2023-08-20 12:09:52 +02:00
5dc8e46080 Added Modpack install instructions
All checks were successful
Build and Publish / Build and Publish Discord Bot (push) Successful in 24s
Build and Publish / Build and Publish Minecraft Mod (push) Successful in 1m36s
2023-08-17 11:43:22 +02:00
1aac53deb8 Fixed spelling mistake
All checks were successful
Build and Publish / Build and Publish Discord Bot (push) Successful in 26s
Build and Publish / Build and Publish Minecraft Mod (push) Successful in 1m41s
2023-08-17 10:54:14 +02:00
0a5d94fd8c Small space issues
All checks were successful
Build and Publish / Build and Publish Discord Bot (push) Successful in 24s
Build and Publish / Build and Publish Minecraft Mod (push) Successful in 1m44s
2023-08-17 10:26:24 +02:00
5f0de3f326 Added nuke command
All checks were successful
Build and Publish / Build and Publish Discord Bot (push) Successful in 28s
Build and Publish / Build and Publish Minecraft Mod (push) Successful in 2m17s
2023-08-17 10:23:42 +02:00
ff29cc1c53 Update discordbot/.gitignore
All checks were successful
Build and Publish / Build and Publish Discord Bot (push) Successful in 24s
Build and Publish / Build and Publish Minecraft Mod (push) Successful in 1m36s
2023-08-15 10:29:29 +02:00
ce3507db62 Delete discordbot/database.sqlite
Some checks reported warnings
Build and Publish / Build and Publish Minecraft Mod (push) Has been cancelled
Build and Publish / Build and Publish Discord Bot (push) Has been cancelled
2023-08-15 10:29:18 +02:00
0739ac9376 Added messages
All checks were successful
Build and Publish / Build and Publish Discord Bot (push) Successful in 50s
Build and Publish / Build and Publish Minecraft Mod (push) Successful in 2m5s
2023-08-15 10:21:10 +02:00
765ab7f8d1 shadowed dependency
All checks were successful
Build and Publish / Build and Publish Discord Bot (push) Successful in 12s
Build and Publish / Build and Publish Minecraft Mod (push) Successful in 1m54s
2023-08-12 12:12:57 +02:00
624af4f5fd Update .gitea/workflows/release.yaml
All checks were successful
Build and Publish / Build and Publish Discord Bot (push) Successful in 11s
Build and Publish / Build and Publish Minecraft Mod (push) Successful in 1m40s
2023-08-12 11:39:20 +02:00
25a1d92e52 Update .gitea/workflows/release.yaml
Some checks reported warnings
Build and Publish / Build and Publish Discord Bot (push) Successful in 11s
Build and Publish / Build and Publish Minecraft Mod (push) Has been cancelled
2023-08-12 11:39:10 +02:00
e523385e5c Update .gitea/workflows/release.yaml
All checks were successful
Build and Publish / Build and Publish Minecraft Mod (push) Successful in 1m44s
Build and Publish / Build and Publish Discord Bot (push) Successful in 10s
2023-08-12 11:35:14 +02:00
9e4a91dd46 fixed ephemeral mistake
Some checks reported warnings
Build and Publish / Build and Publish Discord Bot (push) Successful in 25s
Build and Publish / Build and Publish Minecraft Mod (push) Has been cancelled
2023-08-12 11:34:34 +02:00
d9ae8e729a Update .gitea/workflows/release-nighty.yaml
All checks were successful
Build and Publish / Build and Publish Discord Bot (push) Successful in 26s
Build and Publish / Build and Publish Minecraft Mod (push) Successful in 1m46s
2023-08-12 11:27:02 +02:00
664eafa4cc Update discordbot/Dockerfile
Some checks reported warnings
Build and Publish / Build and Publish Discord Bot (push) Successful in 35s
Build and Publish / Build and Publish Minecraft Mod (push) Has been cancelled
2023-08-12 11:26:33 +02:00
1f810ca533 Update discordbot/Dockerfile
All checks were successful
Build and Publish / Build and Publish Discord Bot (push) Successful in 34s
Build and Publish / Build and Publish Minecraft Mod (push) Successful in 1m46s
2023-08-12 11:22:39 +02:00
64776ad8cf Update discordbot/Dockerfile
Some checks reported warnings
Build and Publish / Build and Publish Minecraft Mod (push) Has been cancelled
Build and Publish / Build and Publish Discord Bot (push) Has been cancelled
2023-08-12 11:22:23 +02:00
e8c2d1495d Update discordbot/Dockerfile
All checks were successful
Build and Publish / Build and Publish Discord Bot (push) Successful in 31s
Build and Publish / Build and Publish Minecraft Mod (push) Successful in 1m46s
2023-08-12 11:15:18 +02:00
8c41ad39c3 Update discordbot/Dockerfile
Some checks failed
Build and Publish / Build and Publish Discord Bot (push) Failing after 23s
Build and Publish / Build and Publish Minecraft Mod (push) Successful in 1m38s
2023-08-12 11:07:40 +02:00
f3c0f7d728 Delete discordbot/database.sqlite
All checks were successful
Build and Publish / Build and Publish Discord Bot (push) Successful in 29s
Build and Publish / Build and Publish Minecraft Mod (push) Successful in 1m38s
2023-08-12 11:05:14 +02:00
217781b4f0 Update .gitea/workflows/release-nighty.yaml
All checks were successful
Build and Publish / Build and Publish Discord Bot (push) Successful in 22s
Build and Publish / Build and Publish Minecraft Mod (push) Successful in 1m28s
2023-08-11 12:42:45 +02:00
b67befd3eb Update .gitea/workflows/release-nighty.yaml
All checks were successful
Build and Publish / Build and Publish Discord Bot (push) Successful in 21s
Build and Publish / Build and Publish Minecraft Mod (push) Successful in 1m30s
2023-08-11 12:37:04 +02:00
d1111732f3 Update .gitea/workflows/release-nighty.yaml
All checks were successful
Build and Publish / Build and Publish Discord Bot (push) Successful in 21s
Build and Publish / Build and Publish Minecraft Mod (push) Successful in 1m31s
2023-08-11 12:32:53 +02:00
3df664614f Update .gitea/workflows/release-nighty.yaml
Some checks failed
Build and Publish / Build and Publish Discord Bot (push) Successful in 24s
Build and Publish / Build and Publish Minecraft Mod (push) Failing after 1m33s
2023-08-11 12:26:09 +02:00
faf823ec37 Update .gitea/workflows/release-nighty.yaml
Some checks failed
Build and Publish / Build and Publish Discord Bot (push) Successful in 21s
Build and Publish / Build and Publish Minecraft Mod (push) Failing after 1m31s
2023-08-11 12:23:37 +02:00
ef355ecd48 Update .gitea/workflows/release-nighty.yaml
All checks were successful
Build and Publish / Build and Publish Discord Bot (push) Successful in 21s
Build and Publish / Build and Publish Minecraft Mod (push) Successful in 1m32s
2023-08-11 12:20:57 +02:00
3968a0e0c8 Update .gitea/workflows/release-nighty.yaml
Some checks failed
Build and Publish / Build and Publish Discord Bot (push) Successful in 21s
Build and Publish / Build and Publish Minecraft Mod (push) Failing after 37s
2023-08-11 12:19:03 +02:00
550542ae50 Update .gitea/workflows/release-nighty.yaml
All checks were successful
Build and Publish / Build and Publish Discord Bot (push) Successful in 21s
Build and Publish / Build and Publish Minecraft Mod (push) Successful in 8s
2023-08-11 12:12:30 +02:00
4c1e01b3c4 Add .gitea/workflows/release-nighty.yaml
All checks were successful
Build and Publish / Build and Publish Discord Bot (push) Successful in 26s
2023-08-11 12:11:00 +02:00
3459e1f733 Update .gitea/workflows/release.yaml 2023-08-11 12:01:53 +02:00
7ad3b82fb4 Update .gitea/workflows/release.yaml
All checks were successful
Build and Publish / Build and Publish Discord Bot (push) Successful in 23s
2023-08-11 11:55:07 +02:00
492248f01b Update .gitea/workflows/release.yaml
Some checks failed
Build and Publish / Build and Publish Discord Bot (push) Failing after 21s
2023-08-11 11:53:45 +02:00
4ec70b3601 Update .gitea/workflows/release.yaml
All checks were successful
Build and Publish / Build and Publish Discord Bot (push) Successful in 35s
2023-08-11 11:51:11 +02:00
e40d9eb14a changed docker auth type
Some checks failed
Build and Publish / Build and Publish Discord Bot (push) Failing after 20s
2023-08-11 11:48:41 +02:00
60a50c3bfb modified ci
Some checks failed
Build and Publish / Build and Publish Discord Bot (push) Failing after 46s
2023-08-11 11:46:17 +02:00
2dcbced91e added ci
Some checks failed
Build and Publish / Build and Publish Discord Bot (push) Failing after 1m10s
2023-08-11 11:43:14 +02:00
981de3d2e5 added assets 2023-08-11 11:18:21 +02:00
eddf87df4d Added a bunch of functions 2023-08-11 11:15:45 +02:00
6f24616c81 Added alot of functions 2023-08-11 11:14:59 +02:00
0f54fbf07e Added minecraft to discord messages 2023-08-05 12:21:30 +02:00
1e72ecdf53 added username system 2023-08-05 11:16:18 +02:00
e5644462b9 Added whitelist function 2023-08-04 19:27:29 +02:00
1b89c4440b Added verifyminecraft function 2023-08-04 17:05:49 +02:00
cf968f198a Added database 2023-08-03 12:06:31 +02:00
b68cb0b219 added basic functions 2023-08-02 14:16:30 +02:00
0c1cc63b9b initialized discord bot 2023-08-02 13:26:48 +02:00
fbc9238e97 added eslint typescript 2023-06-28 14:19:07 +02:00
d52431ffb5 Initialized discord bot version 2
Some checks failed
Build and Deploy / Deploy Web (push) Failing after 1s
Build and Deploy / Deploy Discord Bot (push) Failing after 1s
2023-06-27 19:38:28 +02:00
f5d9aefc0f removed modpack 2023-06-26 15:16:57 +02:00
7678a44945 feat: Added logout function 2023-06-26 15:16:24 +02:00
bbd329a4cf feat: Added Map page
Some checks failed
Build and Deploy / Deploy Web (push) Failing after 1s
Build and Deploy / Deploy Discord Bot (push) Failing after 1s
2023-06-25 17:48:22 +02:00
5685dd5fb7 feat: Added meta data 2023-06-24 13:47:40 +02:00
213 changed files with 2834 additions and 54785 deletions

View File

@@ -1,59 +0,0 @@
name: Build and Deploy
on: [push]
jobs:
Deploy Web:
runs-on: ubuntu-latest
container:
image: catthehacker/ubuntu:act-latest
steps:
- uses: actions/checkout@v3
- name: Use Nodejs
uses: actions/setup-node@v3
with:
node-version: 18
- run: npm install
working-directory: ./web
- run: npm run build
working-directory: ./web
- uses: docker/setup-qemu-action@v2
- uses: docker/setup-buildx-action@v2
- uses: docker/login-action@v2
with:
registry: gitea.xeovalyte.dev
username: ${{ secrets.DOCKER_USERNAME }}
password: ${{ secrets.DOCKER_PASSWORD }}
- run: docker buildx build -t gitea.xeovalyte.dev/xeovalyte/polarcraft-web:latest --load --platform=linux/amd64 ./web
- run: docker push gitea.xeovalyte.dev/xeovalyte/polarcraft-web:latest
Deploy Discord Bot:
runs-on: ubuntu-latest
container:
image: catthehacker/ubuntu:act-latest
steps:
- uses: actions/checkout@v3
- name: Use Nodejs
uses: actions/setup-node@v3
with:
node-version: 18
- run: npm install
working-directory: ./discord-bot
- uses: docker/setup-qemu-action@v2
- uses: docker/setup-buildx-action@v2
- uses: docker/login-action@v2
with:
registry: gitea.xeovalyte.dev
username: ${{ secrets.DOCKER_USERNAME }}
password: ${{ secrets.DOCKER_PASSWORD }}
- run: docker buildx build -t gitea.xeovalyte.dev/xeovalyte/polarcraft-discord:latest --load --platform=linux/amd64 ./discord-bot
- run: docker push gitea.xeovalyte.dev/xeovalyte/polarcraft-discord:latest

View File

@@ -0,0 +1,55 @@
name: Build and Publish
on:
push:
branches:
- 'dev'
jobs:
Build and Publish Discord Bot:
runs-on: ubuntu-latest
container:
image: catthehacker/ubuntu:act-latest
steps:
- uses: actions/checkout@v3
- uses: docker/login-action@v2
with:
registry: gitea.xeovalyte.dev
username: ${{ gitea.actor }}
password: ${{ secrets.DOCKER_PASSWORD }}
- uses: docker/build-push-action@master
with:
context: ./discordbot
push: true
tags: gitea.xeovalyte.dev/xeovalyte/polarcraft:nightly
Build and Publish Minecraft Mod:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Set up JDK
uses: actions/setup-java@v1
with:
java-version: 17
- name: Grant execute permission for gradlew
working-directory: ./mod
run: chmod +x gradlew
- name: Build with Gradle
working-directory: ./mod
run: ./gradlew build
- name: Upload Artifacts
uses: actions/upload-artifact@v3
with:
name: polarcraft-mod.jar
path: |
mod/build/libs/*.jar
!mod/build/libs/*-sources.jar
!mod/build/libs/*-dev.jar

View File

@@ -0,0 +1,53 @@
name: Build and Publish
on:
push:
branches:
- 'main'
jobs:
Build and Publish Discord Bot:
runs-on: ubuntu-latest
container:
image: catthehacker/ubuntu:act-latest
steps:
- uses: actions/checkout@v3
- uses: docker/login-action@v2
with:
registry: gitea.xeovalyte.dev
username: ${{ gitea.actor }}
password: ${{ secrets.DOCKER_PASSWORD }}
- uses: docker/build-push-action@master
with:
context: ./discordbot
push: true
tags: gitea.xeovalyte.dev/xeovalyte/polarcraft:latest
Build and Publish Minecraft Mod:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Set up JDK
uses: actions/setup-java@v1
with:
java-version: 17
- name: Grant execute permission for gradlew
working-directory: ./mod
run: chmod +x gradlew
- name: Build with Gradle
working-directory: ./mod
run: ./gradlew build
- name: Upload Artifacts
uses: actions/upload-artifact@v3
with:
name: polarcraft-mod.jar
path: |
mod/build/libs/*.jar
!mod/build/libs/*-sources.jar
!mod/build/libs/*-dev.jar

View File

@@ -1,11 +0,0 @@
FROM node:18-alpine
WORKDIR /usr/src/app
COPY . .
RUN npm install
EXPOSE 3000
CMD [ "node", "index.js" ]

View File

@@ -1,173 +0,0 @@
const { SlashCommandBuilder } = require('discord.js');
const { QueryType } = require('discord-player');
module.exports = {
data: new SlashCommandBuilder()
.setName('music')
.setDescription('Play and configure music')
.addSubcommand(subcommand => subcommand
.setName('play')
.setDescription('Play music')
.addStringOption(option => option
.setName('link-or-query')
.setDescription('The song or link you want to play')
.setRequired(true)))
.addSubcommand(subcommand => subcommand
.setName('skip')
.setDescription('Skip current song'))
.addSubcommand(subcommand => subcommand
.setName('stop')
.setDescription('Stop current queue'))
.addSubcommand(subcommand => subcommand
.setName('pause')
.setDescription('Pause the current song'))
.addSubcommand(subcommand => subcommand
.setName('shuffle')
.setDescription('Shuffle the queue'))
.addSubcommand(subcommand => subcommand
.setName('resume')
.setDescription('Resume the current song'))
.addSubcommand(subcommand => subcommand
.setName('filter')
.setDescription('Apply a filter')
.addStringOption(option => option
.setName('type')
.setDescription('Type of filter')
.setRequired(true)
.addChoices(
{ name: 'Bassboost', value: 'bassboost_low' },
{ name: 'Nightcore', value: 'nightcore' },
)))
.addSubcommand(subcommand => subcommand
.setName('volume')
.setDescription('Set volume')
.addNumberOption(option => option
.setName('percentage')
.setDescription('The percentage of the volume between 1 and 100')
.setRequired(true))),
async execute({ interaction, createEmbed, client }) {
if (!interaction.member.voice.channelId) return await interaction.reply({ embeds: [createEmbed.basic('You are not in a voice channel!')], ephemeral: true });
if (interaction.guild.members.me.voice.channelId && interaction.member.voice.channelId !== interaction.guild.members.me.voice.channelId) {
return await interaction.reply({ embeds: [createEmbed.basic('You are not in my voice channel!')], ephemeral: true });
}
if (interaction.options.getSubcommand() === 'play') {
const query = interaction.options.getString('link-or-query');
const queue = client.player.createQueue(interaction.guild, {
ytdlOptions: {
filter: 'audioonly',
highWaterMark: 1 << 30,
dlChunkSize: 0,
},
metadata: {
channel: interaction.channel,
},
});
// verify vc connection
try {
if (!queue.connection) await queue.connect(interaction.member.voice.channel);
} catch {
queue.destroy();
return await interaction.reply({ embeds: [createEmbed.basic('Could not join your voice channel!')], ephemeral: true });
}
await interaction.reply({ embeds: [createEmbed.basic('Searching...')], ephemeral: true });
const searchResult = await client.player.search(query, {
requestedBy: interaction.user,
searchEngine: QueryType.AUTO,
});
if (!searchResult || !searchResult.tracks[0]) return await interaction.editReply({ embeds: [createEmbed.basic(`Track or playlist **${query}** not found!`)], ephemeral: true });
searchResult.playlist ? queue.addTracks(searchResult.tracks) : queue.addTrack(searchResult.tracks[0]);
if (!queue.playing) await queue.play();
if (!searchResult.playlist) await interaction.editReply({ embeds: [createEmbed.basic(`Adding track **${searchResult.tracks[0].title}**`)], ephemeral: false });
else await interaction.editReply({ embeds: [createEmbed.basic(`Adding **${searchResult.playlist.tracks.length}** tracks from playlist **${searchResult.playlist.title}**`)], ephemeral: false });
} else if (interaction.options.getSubcommand() === 'skip') {
const queue = client.player.getQueue(interaction.guild);
if (!queue || !queue.playing) return await interaction.reply({ embeds: [createEmbed.basic('No music is being played')] });
const currentTrack = queue.nowPlaying();
const success = queue.skip();
await interaction.reply({ embeds: [createEmbed.basic(success ? `Skipped **${currentTrack.title}**` : 'Something went wrong')] });
} else if (interaction.options.getSubcommand() === 'volume') {
const vol = interaction.options.getNumber('percentage');
const queue = client.player.getQueue(interaction.guild);
if (!queue || !queue.playing) return await interaction.reply({ embeds: [createEmbed.basic('No music is being played')] });
if (vol < 1 || vol > 100) return interaction.reply({ embeds: [createEmbed.basic('Volume must be between 1 and 100')] });
const success = queue.setVolume(vol);
await interaction.reply({ embeds: [createEmbed.basic(success ? `Volume set to **${vol}%**` : 'Something went wrong')] });
} else if (interaction.options.getSubcommand() === 'stop') {
const queue = client.player.getQueue(interaction.guild);
if (!queue || !queue.playing) return await interaction.reply({ embeds: [createEmbed.basic('No music is being played')] });
queue.destroy();
await interaction.reply({ embeds: [createEmbed.basic('Stopped the player')] });
} else if (interaction.options.getSubcommand() === 'pause') {
const queue = client.player.getQueue(interaction.guild);
if (!queue || !queue.playing) return await interaction.reply({ embeds: [createEmbed.basic('No music is being played')] });
queue.setPaused(true);
await interaction.reply({ embeds: [createEmbed.basic('Paused the player')] });
} else if (interaction.options.getSubcommand() === 'resume') {
const queue = client.player.getQueue(interaction.guild);
if (!queue || !queue.playing) return await interaction.reply({ embeds: [createEmbed.basic('No music is being played')] });
queue.setPaused(false);
await interaction.reply({ embeds: [createEmbed.basic('Resumed the player')] });
} else if (interaction.options.getSubcommand() === 'filter') {
const filter = interaction.options.getString('type');
const queue = client.player.getQueue(interaction.guild);
if (!queue || !queue.playing) return await interaction.reply({ embeds: [createEmbed.basic('No music is being played')] });
if (filter === 'bassboost_low') {
await queue.setFilters({
bassboost_low: !queue.getFiltersEnabled().includes('bassboost_low'),
normalizer2: !queue.getFiltersEnabled().includes('bassboost_low'),
});
}
if (filter === 'nightcore') {
await queue.setFilters({
nightcore: !queue.getFiltersEnabled().includes('nightcore'),
});
}
await interaction.reply({ embeds: [createEmbed.basic(queue.getFiltersEnabled().includes(filter) ? `Applied **${filter}** filter` : `Removed **${filter}** filter`)] });
} else if (interaction.options.getSubcommand() === 'shuffle') {
const queue = client.player.getQueue(interaction.guild);
if (!queue || !queue.playing) return await interaction.reply({ embeds: [createEmbed.basic('No music is being played')] });
const success = queue.shuffle();
await interaction.reply({ embeds: [createEmbed.basic(success ? 'The queue has been shuffled' : 'Something went wrong')] });
}
},
};

View File

@@ -1,12 +0,0 @@
const { SlashCommandBuilder } = require('discord.js');
module.exports = {
data: new SlashCommandBuilder()
.setName('ping')
.setDescription('Replies with Pong!'),
async execute({ interaction, createEmbed, client }) {
const reply = await interaction.reply({ embeds: [createEmbed.basic(`Websocket heartbeat: **${client.ws.ping}ms**\n Roundtrip latency: **Pinging...**`)], fetchReply: true, ephemeral: true });
interaction.editReply({ embeds: [createEmbed.basic(`Websocket heartbeat: **${client.ws.ping}ms**\n Roundtrip latency: **${reply.createdTimestamp - interaction.createdTimestamp}ms**`)], emphemeral: true });
},
};

View File

@@ -1,70 +0,0 @@
const { SlashCommandBuilder, PermissionsBitField, ChannelType, ButtonStyle, ButtonBuilder, ActionRowBuilder } = require('discord.js');
module.exports = {
data: new SlashCommandBuilder()
.setName('ticket')
.setDescription('Commands for managing a ticket')
.addSubcommand(subcommand => subcommand
.setName('create')
.setDescription('Create a ticket with you and moderators'))
.addSubcommand(subcommand => subcommand
.setName('close')
.setDescription('Close current ticket')),
async execute({ interaction, createEmbed }) {
if (interaction.options.getSubcommand() === 'create') {
await interaction.reply({ embeds: [createEmbed.basic('Creating ticket channel...')], fetchReply: true, ephemeral: true });
const ticketChannel = await interaction.member.guild.channels.create({
name: `ticket-${interaction.user.username}`,
type: ChannelType.GuildText,
parent: process.env.TICKET_CATEGORY_ID,
permissionOverwrites: [
{
id: interaction.guild.id,
deny: [PermissionsBitField.Flags.ViewChannel],
},
{
id: process.env.MODERATOR_ROLE_ID,
allow: [PermissionsBitField.Flags.ViewChannel],
},
{
id: interaction.user.id,
allow: [PermissionsBitField.Flags.ViewChannel],
},
],
});
await ticketChannel.send({ embeds: [createEmbed.basic(`${interaction.user} created a ticket`)] });
interaction.editReply({ embeds: [createEmbed.basic(`${ticketChannel} has been created`)], emphemeral: true });
} else if (interaction.options.getSubcommand() === 'close') {
if (!interaction.channel.name.startsWith('ticket')) return interaction.reply({ embeds: [createEmbed.basic('You must execute this command inside a ticket channel')], emphemeral: true });
const cancelRow = new ActionRowBuilder()
.addComponents(
new ButtonBuilder()
.setCustomId('cancel')
.setLabel('Cancel')
.setStyle(ButtonStyle.Danger),
);
const closeMessage = await interaction.reply({ embeds: [createEmbed.basic('Closing ticket in 10 seconds...')], components: [cancelRow] });
const collector = closeMessage.createMessageComponentCollector();
const timeout = setTimeout(() => {
try {
interaction.channel.delete();
} catch {}
}, 10000);
collector.on('collect', async () => {
clearTimeout(timeout);
await closeMessage.edit({ embeds: [createEmbed.basic('Ticket closing has been stopped')], components: [] });
});
}
},
};

View File

@@ -1,17 +0,0 @@
const { Events } = require('discord.js');
module.exports = {
name: Events.MessageCreate,
async execute({ log }, message) {
if (message.channelId === process.env.MINECRAFT_CHANNEL_ID && !message.author.bot) {
await fetch(process.env.WEB_HOST + '/api/minecraft/message/chattominecraft', {
method: 'POST',
body: JSON.stringify({
content: message.content,
discordId: message.author.id,
}),
});
}
},
};

View File

@@ -1,17 +0,0 @@
const { Events, EmbedBuilder } = require('discord.js');
module.exports = {
name: Events.GuildMemberAdd,
async execute({ client, log }, member) {
log.Info(`${member.user.username} has joined`);
const newMemberEmbed = new EmbedBuilder()
.setTitle(`${member.user.username} has joined!`)
.setDescription(`Welcome ${member} to the **Polarcraft** Discord server!`)
.setColor(process.env.EMBED_COLOR)
.setThumbnail(member.user.avatarURL());
const channel = await client.channels.cache.get(process.env.LOG_CHANNEL_ID);
channel.send({ embeds: [newMemberEmbed] });
},
};

View File

@@ -1,15 +0,0 @@
const { Events, EmbedBuilder } = require('discord.js');
module.exports = {
name: Events.GuildMemberRemove,
async execute({ client, log }, member) {
log.Info(`${member.user.username} has left`);
const newMemberEmbed = new EmbedBuilder()
.setTitle(`${member.user.username} has left!`)
.setColor(process.env.EMBED_COLOR);
const channel = await client.channels.cache.get(process.env.LOG_CHANNEL_ID);
channel.send({ embeds: [newMemberEmbed] });
},
};

View File

@@ -1,26 +0,0 @@
const { Events } = require('discord.js');
module.exports = {
name: Events.InteractionCreate,
async execute({ log, createEmbed, client }, interaction) {
if (interaction.isChatInputCommand()) {
const command = interaction.client.commands.get(interaction.commandName);
if (!command) {
return log.Error(`No command matching ${interaction.commandName} was found`);
} else {
log.Info(`${interaction.user.username} executed command ${interaction.commandName}`);
}
try {
await command.execute({ interaction, log, createEmbed, client });
} catch (error) {
log.Error(error);
await interaction.reply({ content: 'There was an error while executing this command!', ephemeral: true });
}
}
},
};

View File

@@ -1,11 +0,0 @@
const { Events } = require('discord.js');
module.exports = {
name: Events.ClientReady,
once: true,
execute({ client, log }) {
log.Info(`Ready! Logged in as ${client.user.tag}`);
require('../functions/registerCommands.js').registerCommands(log);
},
};

View File

@@ -1,12 +0,0 @@
const { EmbedBuilder } = require('discord.js');
const dotenv = require('dotenv');
dotenv.config();
const basic = (description) => {
return new EmbedBuilder()
.setColor(process.env.EMBED_COLOR)
.setDescription(description);
};
module.exports = { basic };

View File

@@ -1,31 +0,0 @@
const { EmbedBuilder } = require('discord.js');
const registerEvents = ({ client }) => {
client.player.on('trackStart', (queue, track) => {
const nowPlayingEmbed = new EmbedBuilder()
.setTitle('Now Playing')
.setColor(process.env.EMBED_COLOR)
.setDescription(`[${track.title}](${track.url})`)
.addFields(
{ name: 'Requested By', value: `${track.requestedBy}`, inline: true },
{ name: 'Duration', value: track.duration, inline: true },
{ name: 'Queue', value: `${queue.tracks.length} song(s)`, inline: true },
{ name: 'Author', value: track.author, inline: true },
{ name: 'Source', value: track.source, inline: true },
{ name: 'Volume', value: `${queue.options.initialVolume}%`, inline: true },
{ name: 'Filters', value: queue.getFiltersEnabled().join('\n') || 'No filters active', inline: false },
)
.setThumbnail(track.thumbnail)
.setTimestamp();
queue.metadata.channel.send({ embeds: [nowPlayingEmbed] });
});
client.player.on('error', (queue, error) => {
console.log(error);
});
};
module.exports = { registerEvents };

View File

@@ -1,48 +0,0 @@
const { REST, Routes } = require('discord.js');
const fs = require('node:fs');
const dotenv = require('dotenv');
dotenv.config();
const registerCommands = (log) => {
const commands = [];
// Grab all the command files from the commands directory you created earlier
const commandFiles = fs.readdirSync('./commands').filter(file => file.endsWith('.js'));
// Grab the SlashCommandBuilder#toJSON() output of each command's data for deployment
for (const file of commandFiles) {
const command = require(`../commands/${file}`);
commands.push(command.data.toJSON());
}
// Construct and prepare an instance of the REST module
const rest = new REST({ version: '10' }).setToken(process.env.DISCORD_TOKEN);
// and deploy your commands!
(async () => {
try {
log.Info(`Started refreshing ${commands.length} application (/) commands.`);
// The put method is used to fully refresh all commands in the guild with the current set
let data = null;
if (process.env.GUILD_ID !== 'production') {
data = await rest.put(
Routes.applicationGuildCommands(process.env.CLIENT_ID, process.env.GUILD_ID),
{ body: commands },
);
} else {
data = await rest.put(
Routes.applicationGuildCommands(process.env.CLIENT_ID),
{ body: commands },
);
}
log.Info(`Successfully reloaded ${data.length} application (/) commands.`);
} catch (error) {
// And of course, make sure you catch and log any errors!
log.Error(error);
}
})();
};
module.exports = { registerCommands };

View File

@@ -1,25 +0,0 @@
{
"type": "commonjs",
"name": "discord-bot",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"lint": "eslint .",
"lint-fix": "eslint . --fix"
},
"author": "",
"license": "ISC",
"dependencies": {
"@discord-player/extractor": "^3.0.2",
"@discordjs/opus": "^0.8.0",
"chalk": "^4.1.2",
"discord-player": "^5.3.2",
"discord.js": "^14.7.1",
"distube": "^4.0.4",
"dotenv": "^16.0.3",
"eslint": "^8.29.0",
"express": "^4.18.2",
"ytdl-core": "^4.11.4"
}
}

View File

@@ -1,38 +0,0 @@
const { WebhookClient, EmbedBuilder } = require('discord.js');
const express = require('express');
const router = express.Router();
const webhookClient = new WebhookClient({ url: process.env.MINECRAFT_WEBHOOK_URL });
router.post('/sendchatmessage', (req, res) => {
const { content, username, avatarURL } = req.body;
if (!username || !content || !avatarURL) return res.status(400).send({ error: 'Content, username and avatar_url are required' });
webhookClient.send({
content: content,
username: username,
avatarURL: avatarURL,
});
res.send({ data: 'Test data' });
});
router.post('/sendgamemessage', (req, res) => {
const { content, avatarURL } = req.body;
if (!content || !avatarURL) return res.status(400).send({ error: 'Content, username and avatar_url are required' });
const messageEmbed = new EmbedBuilder()
.setColor(process.env.EMBED_COLOR)
.setAuthor({ name: content, iconURL: avatarURL });
webhookClient.send({
embeds: [messageEmbed],
username: 'Server',
});
res.send({ data: 'Test data' });
});
module.exports = router;

View File

@@ -1,145 +0,0 @@
const express = require('express');
const index = require('../index');
const { PermissionsBitField, ChannelType } = require('discord.js');
const router = express.Router();
router.post('/createchannels', async (req, res) => {
const { name, discordId } = req.body;
if (!name || !discordId) return res.status(400).send({ error: 'Name en discordId zijn vereist' });
try {
const guild = await index.client.guilds.fetch(process.env.GUILD_ID);
const category = await guild.channels.fetch(process.env.TEAM_CATEGORY_ID);
const member = await guild.members.fetch(discordId);
const textChannel = await guild.channels.create({
name: name,
type: ChannelType.GuildText,
parent: category,
permissionOverwrites: [
{
id: guild.id,
deny: [PermissionsBitField.Flags.ViewChannel],
},
{
id: member.id,
allow: [PermissionsBitField.Flags.ViewChannel],
},
],
});
const voiceChannel = await guild.channels.create({
name: name,
type: ChannelType.GuildVoice,
parent: category,
permissionOverwrites: [
{
id: guild.id,
deny: [PermissionsBitField.Flags.ViewChannel],
},
{
id: member.id,
allow: [PermissionsBitField.Flags.ViewChannel],
},
],
});
res.send({ textChannel, voiceChannel });
} catch (e) {
console.log(e);
return res.status(500).send({ error: 'Error tijdens het maken van discord channels' });
}
});
router.post('/deletechannels', async (req, res) => {
const { textChannelId, voiceChannelId } = req.body;
if (!textChannelId, !voiceChannelId) return res.status(400).send({ error: 'textChannelId en voiceChannelId zijn vereist' });
try {
const guild = await index.client.guilds.fetch(process.env.GUILD_ID);
const textChannel = await guild.channels.fetch(textChannelId);
const voiceChannel = await guild.channels.fetch(voiceChannelId);
await textChannel.delete();
await voiceChannel.delete();
res.send({ status: 'success' });
} catch (e) {
console.log(e);
return res.status(500).send({ error: 'Error tijdens het verwijderen van discord channels' });
}
});
router.post('/removeteammember', async (req, res) => {
const { textChannelId, voiceChannelId, discordId } = req.body;
if (!textChannelId, !voiceChannelId, !discordId) return res.status(400).send({ error: 'textChannelId, voiceChannelId en discordId zijn vereist' });
try {
const guild = await index.client.guilds.fetch(process.env.GUILD_ID);
const member = await guild.members.fetch(discordId);
const textChannel = await guild.channels.fetch(textChannelId);
const voiceChannel = await guild.channels.fetch(voiceChannelId);
await textChannel.permissionOverwrites.delete(member);
await voiceChannel.permissionOverwrites.delete(member);
res.send({ status: 'success' });
} catch (e) {
console.log(e);
return res.status(500).send({ error: 'Error tijdens het verwijderen van een team member' });
}
});
router.post('/addteammember', async (req, res) => {
const { textChannelId, voiceChannelId, discordId } = req.body;
if (!textChannelId, !voiceChannelId, !discordId) return res.status(400).send({ error: 'textChannelId, voiceChannelId en discordId zijn vereist' });
try {
const guild = await index.client.guilds.fetch(process.env.GUILD_ID);
const member = await guild.members.fetch(discordId);
const textChannel = await guild.channels.fetch(textChannelId);
const voiceChannel = await guild.channels.fetch(voiceChannelId);
await textChannel.permissionOverwrites.edit(member, { ViewChannel: true });
await voiceChannel.permissionOverwrites.edit(member, { ViewChannel: true });
res.send({ status: 'success' });
} catch (e) {
console.log(e);
return res.status(500).send({ error: 'Error tijdens het toevoegen van team member' });
}
});
router.post('/edit', async (req, res) => {
const { textChannelId, voiceChannelId, name } = req.body;
if (!textChannelId, !voiceChannelId, !name) return res.status(400).send({ error: 'textChannelId, voiceChannelId en name zijn vereist' });
try {
const guild = await index.client.guilds.fetch(process.env.GUILD_ID);
const textChannel = await guild.channels.fetch(textChannelId);
const voiceChannel = await guild.channels.fetch(voiceChannelId);
await textChannel.edit({ name: name });
await voiceChannel.edit({ name: name });
res.send({ status: 'success' });
} catch (e) {
console.log(e);
return res.status(500).send({ error: 'Error tijds het veranderen van Discord channel naam' });
}
});
module.exports = router;

View File

@@ -1,47 +0,0 @@
const express = require('express');
const index = require('../index');
const router = express.Router();
router.post('/changenickname', async (req, res) => {
const { nickname, discordId } = req.body;
if (!nickname || !discordId) return res.status(400).send({ error: 'Nickname en discordId zijn vereist' });
const nick = nickname.length > 32 ? nickname.slice(0, 32) : nickname;
try {
const guild = await index.client.guilds.fetch(process.env.GUILD_ID);
const member = await guild.members.fetch(discordId);
await member.edit({ nick: nick });
} catch (e) {
console.log(e);
return res.status(500).send({ error: 'Error tijds het veranderen van de nickname' });
}
res.send({ status: 'success' });
});
router.post('/ban', async (req, res) => {
const { discordId, reason } = req.body;
if (!reason || !discordId) return res.status(400).send({ error: 'Reason en discordId zijn vereist' });
try {
const guild = await index.client.guilds.fetch(process.env.GUILD_ID);
const member = await guild.members.fetch(discordId);
await member.ban({ deleteMessageSeconds: 24 * 3600, reason: reason });
} catch (e) {
console.log(e);
return res.status(500).send({ error: 'Error tijds het bannen van gebruiker' });
}
res.send({ status: 'success' });
});
module.exports = router;

View File

@@ -5,7 +5,8 @@
"es6": true
},
"parserOptions": {
"ecmaVersion": 2021
"ecmaVersion": 2021,
"sourceType": "module"
},
"rules": {
"arrow-spacing": ["warn", { "before": true, "after": true }],

View File

@@ -1,2 +1,3 @@
.env
node_modules
database.sqlite

13
discordbot/Dockerfile Normal file
View File

@@ -0,0 +1,13 @@
FROM node:18-alpine
WORKDIR /usr/src/app
COPY . .
RUN apk update && apk upgrade
RUN apk add --no-cache sqlite
RUN npm install
RUN npm install --save sqlite3
CMD ["node", "index.js"]

View File

@@ -0,0 +1,29 @@
const { SlashCommandBuilder } = require('discord.js');
const { simpleEmbed } = require('../functions/embeds.js');
const { Users } = require('../functions/models.js');
module.exports = {
data: new SlashCommandBuilder()
.setName('adduser')
.setDescription('Add a user to the system')
.addUserOption(option => option
.setName('user')
.setDescription('The user to add')),
async execute(interaction) {
const user = interaction.options.getUser('user') ? interaction.options.getUser('user') : interaction.user;
try {
await Users.create({
id: user.id,
rawUsername: user.globalName,
});
await interaction.reply({ embeds: [simpleEmbed('Added user to the system')], ephemeral: true });
} catch (error) {
console.error(error);
await interaction.reply({ embeds: [simpleEmbed('There was an error while adding the user')], ephemeral: true });
}
},
};

View File

@@ -0,0 +1,49 @@
const { SlashCommandBuilder } = require('discord.js');
const { simpleEmbed } = require('../functions/embeds.js');
const { Users } = require('../functions/models.js');
const { client } = require('../index.js');
module.exports = {
data: new SlashCommandBuilder()
.setName('ban')
.setDescription('Ban a user')
.setDefaultMemberPermissions(0)
.addUserOption(option => option
.setName('user')
.setDescription('The user to ban')
.setRequired(true))
.addStringOption(option => option
.setName('reason')
.setDescription('Why ban the user')
.setRequired(true)),
async execute(interaction) {
const member = interaction.options.getMember('user');
const reason = interaction.options.getString('reason');
try {
await member.ban({ reason });
} catch (error) {
console.error(error);
return await interaction.reply({ embeds: [simpleEmbed(`Error while banning ${member}`)], ephemeral: true });
}
const userInstance = await Users.findOne({ where: { id: member.id } });
if (!userInstance) return await interaction.reply({ embeds: [simpleEmbed('Error while getting user information')], ephemeral: true });
if (userInstance.minecraftUuid) {
await fetch(process.env.MINECRAFT_HOST + '/console', {
method: 'POST',
headers: {
'content-type': 'text/plain',
},
body: `ban ${userInstance.minecraftUuid} ${reason}`,
});
}
const channel = client.channels.cache.get(process.env.MOD_LOG_CHANNEL_ID);
await channel.send({ embeds: [simpleEmbed(`${interaction.user} banned ${member}, reason: **${reason}**`)] });
await interaction.reply({ embeds: [simpleEmbed(`Banned ${member}`)], ephemeral: true });
},
};

View File

@@ -1,4 +1,5 @@
const { SlashCommandBuilder, PermissionFlagsBits } = require('discord.js');
const { simpleEmbed } = require('../functions/embeds.js');
module.exports = {
data: new SlashCommandBuilder()
@@ -10,15 +11,13 @@ module.exports = {
.setDescription('The amount of messages to clear')
.setRequired(true)),
async execute({ interaction, createEmbed, client }) {
async execute(interaction) {
const amount = interaction.options.getNumber('amount');
if (amount < 1 || amount > 100) return await interaction.reply({ embeds: [createEmbed.basic('The amount must be between 1-100')] });
if (amount < 1 || amount > 100) return await interaction.reply({ embeds: [simpleEmbed('The amount must be between 1-100')] });
const channel = client.channels.cache.get(interaction.channelId);
interaction.channel.bulkDelete(amount, true);
channel.bulkDelete(amount);
await interaction.reply({ embeds: [createEmbed.basic(`Cleared **${amount}** messages`)], ephemeral: true });
await interaction.reply({ embeds: [simpleEmbed(`Cleared **${amount}** messages`)], ephemeral: true });
},
};

View File

@@ -0,0 +1,11 @@
const { SlashCommandBuilder } = require('discord.js');
const { simpleEmbed } = require('../functions/embeds.js');
module.exports = {
data: new SlashCommandBuilder()
.setName('dennis')
.setDescription('Dennis.'),
async execute(interaction) {
await interaction.reply({ embeds: [simpleEmbed('Dennis is koel')], ephemeral: true });
},
};

View File

@@ -0,0 +1,62 @@
const { SlashCommandBuilder, EmbedBuilder } = require('discord.js');
module.exports = {
data: new SlashCommandBuilder()
.setName('message')
.setDescription('Send a default game message')
.setDefaultMemberPermissions(0)
.addStringOption(option => option
.setName('option')
.setDescription('Which message to send')
.setRequired(true)
.addChoices(
{ name: 'welcome', value: 'welcome' },
{ name: 'moderators', value: 'moderators' },
)),
async execute(interaction) {
const option = interaction.options.getString('option');
if (option === 'welcome') {
const embed0 = new EmbedBuilder()
.setTitle('Rules')
.setColor(process.env.EMBED_COLOR)
.setDescription('De regels zijn dit seizoen niet concreet. Zorg ervoor dat de ervaring voor iedereen leuk is en blijft. Een grapje maken mag, maar verpest niet iemand anders zijn ervaring.');
const embed1 = new EmbedBuilder()
.setTitle('Commands')
.setColor(process.env.EMBED_COLOR)
.addFields(
{ name: 'Whitelist', value: 'Join de Minecraft server en vul de gekregen code in door de `/whitelist` commando uit te voeren in discord. Door het commando `/removewhitelist` uit te voeren verwijder je jezelf van de whitelist.\n\u200B' },
{ name: 'Team', value: '**Team maken:** Voer het commando `/team create` uit in discord. Kleur kan je uitzoeken op deze website: [HTML Color Codes](https://htmlcolorcodes.com/color-picker/)\n\n**Inviten:** Voer het commando `/team invite <user>` uit in discord. Deze persoon zal een invite krijgen en deze accepteren of weigeren.\n\n**Leave:** Voer het commando `/team leave` uit om het team te verlaten.\n\u200B' },
{ name: 'Username', value: 'Door het commando `/setusername <type>` uit te voeren kan gekozen worden tussen de Minecraft of Discord username. Deze username zal op Discord en Minecraft weergegeven worden.\n\u200B' },
{ name: 'Minecraft', value: 'Door het commando `/map <hide/show>` uit te voeren in Minecraft kan gekozen om zichtbaar te zijn op [deze map](https://polarcraft.xeovalyte.com/) of niet' },
);
const embed2 = new EmbedBuilder()
.setTitle('Polarcraft Modpack')
.setColor(process.env.EMBED_COLOR)
.addFields({ name: 'Installeer Instructies', value: `
**1.** Installeer de [Modrinth launcher](https://modrinth.com/app) en log in\n
**2.** Klik op het zoek icoon op de linker balk en zoek voor "Polarcraft Modpack"\n
**3.** Klik vervolgens op "install"\n
**4.** Klaar! Klik op "Play" om Minecraft op te starten\n
` })
.setDescription('De Polarcraft Modpack is niet nodig, maar wel handig. In deze modpack zitten mods voor betere performance en Proximity chat mod. Als je er voor kiest om deze modpack niet te gebruiken is het leuk om zelf de [Plasmo Voice](https://modrinth.com/plugin/plasmo-voice) mod te installeren.');
const embed3 = new EmbedBuilder()
.setTitle('Links')
.setColor(process.env.EMBED_COLOR)
.setDescription('-> IP: polarcraft.xeovalyte.com\n-> [Minecraft Map](https://polarcraft.xeovalyte.com)\n-> [Polarcraft Modpack](https://modrinth.com/modpack/polarcraft-modpack)');
await interaction.reply({ embeds: [embed0, embed1, embed2, embed3] });
} else if (option === 'moderators') {
const embed = new EmbedBuilder()
.setTitle('Commands')
.setColor(process.env.EMBED_COLOR)
.setDescription('`/suspend <user> <time> <reason>` Dit commando zorgt ervoor dat een persoon tijdelijk niks kan doen. Gebruik dit als er bijvoorbeeld gegriefd wordt\n\n`/nuke` Dit commando zet de server in maintenance mode waardoor niemand meer kan joinen');
await interaction.reply({ embeds: [embed] });
}
},
};

View File

@@ -0,0 +1,21 @@
const { SlashCommandBuilder } = require('discord.js');
const { simpleEmbed } = require('../functions/embeds.js');
module.exports = {
data: new SlashCommandBuilder()
.setName('nuke')
.setDescription('Put the server in maintenance mode')
.setDefaultMemberPermissions(0),
async execute(interaction) {
await fetch(process.env.MINECRAFT_HOST + '/console', {
method: 'POST',
headers: {
'content-type': 'text/plain',
},
body: 'maintenance on',
});
await interaction.reply({ embeds: [simpleEmbed('Nuked server!')], ephemeral: true });
},
};

View File

@@ -0,0 +1,14 @@
const { SlashCommandBuilder } = require('discord.js');
const { simpleEmbed } = require('../functions/embeds.js');
const { client } = require('../index.js');
module.exports = {
data: new SlashCommandBuilder()
.setName('ping')
.setDescription('Replies with Pong!'),
async execute(interaction) {
const reply = await interaction.reply({ embeds: [simpleEmbed(`Websocket heartbeat: **${client.ws.ping}ms**\n Roundtrip latency: **Pinging...**`)], fetchReply: true, ephemeral: true });
interaction.editReply({ embeds: [simpleEmbed(`Websocket heartbeat: **${client.ws.ping}ms**\n Roundtrip latency: **${reply.createdTimestamp - interaction.createdTimestamp}ms**`)], ephemeral: true });
},
};

View File

@@ -0,0 +1,31 @@
const { SlashCommandBuilder } = require('discord.js');
const { simpleEmbed } = require('../functions/embeds.js');
const { Minecraft, Users } = require('../functions/models.js');
const { applyUsername } = require('../functions/utils.js');
module.exports = {
data: new SlashCommandBuilder()
.setName('removewhitelist')
.setDescription('Remove yourself from the whitelist'),
async execute(interaction) {
try {
const user = await Users.findOne({ where: { id: interaction.user.id } });
if (!user.minecraftUuid) return await interaction.reply({ embeds: [simpleEmbed('You are not whitelisted')], ephemeral: true });
await Minecraft.destroy({ where: { uuid: user.minecraftUuid } });
await applyUsername(user, interaction.member);
const role = await interaction.guild.roles.fetch(process.env.MINECRAFT_ROLE_ID);
await interaction.member.roles.remove(role);
await interaction.reply({ embeds: [simpleEmbed('Successfully removed you from the whitelist')], ephemeral: true });
} catch (error) {
console.error(error);
await interaction.reply({ embeds: [simpleEmbed('There was an error while removing you from the whitelist')], ephemeral: true });
}
},
};

View File

@@ -0,0 +1,38 @@
const { SlashCommandBuilder } = require('discord.js');
const { simpleEmbed } = require('../functions/embeds.js');
const { Users } = require('../functions/models.js');
const { applyUsername } = require('../functions/utils.js');
module.exports = {
data: new SlashCommandBuilder()
.setName('setusername')
.setDescription('Choose between Discord or Minecraft username')
.addStringOption(option => option
.setName('type')
.setDescription('Discord or Minecraft')
.setRequired(true)
.addChoices(
{ name: 'Discord', value: 'discord' },
{ name: 'Minecraft', value: 'minecraft' },
)),
async execute(interaction) {
const usernameType = interaction.options.getString('type');
try {
const user = await Users.findOne({ where: { id: interaction.user.id } });
user.useMinecraftUsername = usernameType === 'minecraft' ? true : false;
await user.save();
await applyUsername(user, interaction.member);
await interaction.reply({ embeds: [simpleEmbed('Successfully changed your username type')], ephemeral: true });
} catch (error) {
console.error(error);
await interaction.reply({ embeds: [simpleEmbed('There was an error while changing your username type')], ephemeral: true });
}
},
};

View File

@@ -0,0 +1,49 @@
const { SlashCommandBuilder } = require('discord.js');
const { simpleEmbed } = require('../functions/embeds.js');
const { Users } = require('../functions/models.js');
const { client } = require('../index.js');
module.exports = {
data: new SlashCommandBuilder()
.setName('suspend')
.setDescription('Suspend a user')
.setDefaultMemberPermissions(0)
.addUserOption(option => option
.setName('user')
.setDescription('The user to suspend')
.setRequired(true))
.addNumberOption(option => option
.setName('time')
.setDescription('The amount of time to suspend the user in minutes')
.setRequired(true))
.addStringOption(option => option
.setName('reason')
.setDescription('Why suspend the user')
.setRequired(true)),
async execute(interaction) {
const time = interaction.options.getNumber('time');
const member = interaction.options.getMember('user');
const reason = interaction.options.getString('reason');
await member.timeout(time * 60 * 1000, reason);
const user = await Users.findOne({ where: { id: member.id } });
if (!user) return await interaction.reply({ embeds: [simpleEmbed('Error while getting user information')], ephemeral: true });
if (user.minecraftUuid) {
await fetch(process.env.MINECRAFT_HOST + '/console', {
method: 'POST',
headers: {
'content-type': 'text/plain',
},
body: `tempban ${user.minecraftUuid} ${time}m ${reason}`,
});
}
const channel = client.channels.cache.get(process.env.MOD_LOG_CHANNEL_ID);
await channel.send({ embeds: [simpleEmbed(`${interaction.user} suspended ${member} for **${time}** minutes, reason: **${reason}**`)] });
await interaction.reply({ embeds: [simpleEmbed(`Suspended ${member} for **${time}** minutes`)], ephemeral: true });
},
};

208
discordbot/commands/team.js Normal file
View File

@@ -0,0 +1,208 @@
const { SlashCommandBuilder, ModalBuilder, TextInputStyle, TextInputBuilder, ActionRowBuilder, ChannelType, PermissionsBitField, ButtonBuilder, ButtonStyle, ComponentType } = require('discord.js');
const { simpleEmbed } = require('../functions/embeds.js');
const { Users, Team } = require('../functions/models.js');
const { applyUsername } = require('../functions/utils.js');
const { client } = require('../index.js');
module.exports = {
data: new SlashCommandBuilder()
.setName('team')
.setDescription('Team command')
.addSubcommand(subcommand => subcommand
.setName('create')
.setDescription('Create a team'))
.addSubcommand(subcommand => subcommand
.setName('invite')
.setDescription('Invite an user')
.addUserOption(option => option
.setName('user')
.setDescription('The user to invite')
.setRequired(true)))
.addSubcommand(subcommand => subcommand
.setName('leave')
.setDescription('Leave your team')),
async execute(interaction) {
const user = await Users.findOne({ where: { id: interaction.user.id } });
if (!user) return await interaction.reply({ embeds: [simpleEmbed('Error while getting user information')], ephemeral: true });
if (interaction.options.getSubcommand() === 'create') {
if (user.teamId) return await interaction.reply({ embeds: [simpleEmbed('You are already in a team')], ephemeral: true });
const modal = new ModalBuilder()
.setCustomId('teamCreate')
.setTitle('Create team');
const nameInput = new TextInputBuilder()
.setCustomId('nameInput')
.setLabel('Team name')
.setMinLength(3)
.setMaxLength(16)
.setStyle(TextInputStyle.Short);
const colorInput = new TextInputBuilder()
.setCustomId('colorInput')
.setLabel('Team color (hex)')
.setStyle(TextInputStyle.Short)
.setPlaceholder('#00ff00');
const firstActionRow = new ActionRowBuilder().addComponents(nameInput);
const secondActionRow = new ActionRowBuilder().addComponents(colorInput);
modal.addComponents(firstActionRow, secondActionRow);
await interaction.showModal(modal);
try {
const filter = (filterInteraction) => filterInteraction.customId === 'teamCreate';
const modalInteraction = await interaction.awaitModalSubmit({ filter, time: 10 * 60 * 1000 });
const teamName = modalInteraction.fields.getTextInputValue('nameInput');
const teamColor = modalInteraction.fields.getTextInputValue('colorInput');
if (!/^[a-zA-Z0-9]+$/.test(teamName)) return await modalInteraction.reply({ embeds: [simpleEmbed('Team name can only include alphanumeric characters')], ephemeral: true });
if (!/^#([0-9A-Fa-f]{3}|[0-9A-Fa-f]{6})$/.test(teamColor)) return await modalInteraction.reply({ embeds: [simpleEmbed('Team color must be a valid hex code. [Color Picker](https://htmlcolorcodes.com/color-picker/)')], ephemeral: true });
const guild = await client.guilds.fetch(process.env.GUILD_ID);
const category = await guild.channels.fetch(process.env.TEAM_CATEGORY_ID);
const textChannel = await guild.channels.create({
name: teamName,
type: ChannelType.GuildText,
parent: category,
permissionOverwrites: [
{
id: guild.id,
deny: [PermissionsBitField.Flags.ViewChannel],
},
{
id: interaction.member.id,
allow: [PermissionsBitField.Flags.ViewChannel],
},
],
});
const voiceChannel = await guild.channels.create({
name: teamName,
type: ChannelType.GuildVoice,
parent: category,
permissionOverwrites: [
{
id: guild.id,
deny: [PermissionsBitField.Flags.ViewChannel],
},
{
id: interaction.member.id,
allow: [PermissionsBitField.Flags.ViewChannel],
},
],
});
const team = await Team.create({
name: teamName,
color: teamColor,
textChannelId: textChannel.id,
voiceChannelId: voiceChannel.id,
});
await team.addMembers([ user ]);
await applyUsername(user, interaction.member);
await modalInteraction.reply({ embeds: [simpleEmbed(`Successfully created team **${teamName}**`)], ephemeral: true });
} catch (error) {
console.error(error);
}
} else if (interaction.options.getSubcommand() === 'leave') {
if (!user.teamId) return await interaction.reply({ embeds: [simpleEmbed('You are not in a team')], ephemeral: true });
const team = await user.getTeam();
await team.removeMember(user);
const guild = await client.guilds.fetch(process.env.GUILD_ID);
const textChannel = await guild.channels.fetch(team.textChannelId);
const voiceChannel = await guild.channels.fetch(team.voiceChannelId);
if (await team.countMembers() <= 0) {
await textChannel.delete();
await voiceChannel.delete();
await team.destroy();
} else {
await textChannel.permissionOverwrites.delete(interaction.member);
await voiceChannel.permissionOverwrites.delete(interaction.member);
}
await applyUsername(user, interaction.member);
await interaction.reply({ embeds: [simpleEmbed('Successfully left team')], ephemeral: true });
} else if (interaction.options.getSubcommand() === 'invite') {
if (!user.teamId) return await interaction.reply({ embeds: [simpleEmbed('You are not in a team')], ephemeral: true });
const invitedUser = interaction.options.getUser('user');
if (interaction.user.id === invitedUser.id) return await interaction.reply({ embeds: [simpleEmbed('You cannot invite yourself')], ephemeral: true });
const invitedUserInstance = await Users.findOne({ where: { id: invitedUser.id } });
if (invitedUserInstance.teamId) return await interaction.reply({ embeds: [simpleEmbed('The user you are trying already is in a team')], ephemeral: true });
const team = await user.getTeam();
const acceptButton = new ButtonBuilder()
.setCustomId('accept')
.setLabel('Accept')
.setStyle(ButtonStyle.Success);
const denyButton = new ButtonBuilder()
.setCustomId('deny')
.setLabel('Deny')
.setStyle(ButtonStyle.Danger);
const row = new ActionRowBuilder()
.addComponents(acceptButton, denyButton);
const inviteMessage = await invitedUser.send({
embeds: [simpleEmbed(`**${user.rawUsername}** invited you to join team **${team.name}**`)],
components: [row],
});
await interaction.reply({ embeds: [simpleEmbed(`Successfully invited ${invitedUser} to your team`)], ephemeral: true });
const collector = inviteMessage.createMessageComponentCollector({ componentType: ComponentType.Button, time: 60 * 60 * 1000 });
collector.on('collect', async i => {
try {
if (i.customId === 'accept') {
await invitedUserInstance.reload();
if (invitedUserInstance.teamId) return await i.message.edit({ embeds: [simpleEmbed('You are already in a team')], components: [] });
await team.addMember(i.user.id);
const guild = await client.guilds.fetch(process.env.GUILD_ID);
const member = await guild.members.fetch(i.user.id);
const textChannel = await guild.channels.fetch(team.textChannelId);
const voiceChannel = await guild.channels.fetch(team.voiceChannelId);
await textChannel.permissionOverwrites.edit(member, { ViewChannel: true });
await voiceChannel.permissionOverwrites.edit(member, { ViewChannel: true });
await applyUsername(invitedUserInstance, member);
await i.message.edit({ embeds: [simpleEmbed(`Successfully joined team **${team.name}**`)], components: [] });
} else if (i.customId === 'deny') {
await i.message.edit({ embeds: [simpleEmbed(`Successfully denied the request to join team **${team.name}**`)], components: [] });
}
} catch (error) {
console.error(error);
}
});
collector.on('end', async () => {
inviteMessage.edit({ embeds: [simpleEmbed('Confirmation not received within 1 hour, cancelling')], components: [] });
});
}
},
};

View File

@@ -0,0 +1,51 @@
const { SlashCommandBuilder } = require('discord.js');
const { simpleEmbed } = require('../functions/embeds.js');
const { Minecraft, Users } = require('../functions/models.js');
const { applyUsername } = require('../functions/utils.js');
module.exports = {
data: new SlashCommandBuilder()
.setName('whitelist')
.setDescription('Whitelist yourself on the Minecraft server')
.addStringOption(option => option
.setName('code')
.setDescription('6 digit code from Minecraft')
.setRequired(true)),
async execute(interaction) {
const code = interaction.options.getString('code');
if (code.length !== 6) return await interaction.reply({ embeds: [simpleEmbed('The code must be 6 digits long')], ephemeral: true });
const user = await Users.findOne({ where: { id: interaction.user.id } });
if (!user) return await interaction.reply({ embeds: [simpleEmbed('There was an error while finding the user')], ephemeral: true });
if (user.minecraftUuid) return await interaction.reply({ embeds: [simpleEmbed('You are already whitelisted')], ephemeral: true });
try {
const minecraftCol = await Minecraft.findOne({ where: { code: code } });
if (!minecraftCol) return await interaction.reply({ embeds: [simpleEmbed('The code was not linked with a Minecraft account')], ephemeral: true });
if (minecraftCol.whitelisted) return await interaction.reply({ embeds: [simpleEmbed('Minecraft account already whitelisted')], ephemeral: true });
minecraftCol.whitelisted = true;
delete minecraftCol.code;
user.minecraftUuid = minecraftCol.uuid;
await minecraftCol.save();
await user.save();
await applyUsername(user, interaction.member);
const role = await interaction.guild.roles.fetch(process.env.MINECRAFT_ROLE_ID);
await interaction.member.roles.add(role);
await interaction.reply({ embeds: [simpleEmbed('You are successfully whitelisted')], ephemeral: true });
} catch (error) {
console.error(error);
}
},
};

View File

@@ -0,0 +1,26 @@
const { Events, EmbedBuilder } = require('discord.js');
const { client } = require('../index.js');
const { Users } = require('../functions/models');
module.exports = {
name: Events.GuildMemberAdd,
async execute(member) {
const addMemberEmbed = new EmbedBuilder()
.setTitle(`${member.user.globalName} has joined!`)
.setDescription(`Welcome ${member} to the **Polarcraft** Discord server!`)
.setColor(process.env.EMBED_COLOR)
.setThumbnail(member.user.avatarURL());
const channel = client.channels.cache.get(process.env.LOG_CHANNEL_ID);
await channel.send({ embeds: [addMemberEmbed] });
try {
await Users.create({
id: member.user.id,
});
} catch (error) {
if (error.name === 'SequelizeUniqueConstraintError') return;
console.error(error);
}
},
};

View File

@@ -0,0 +1,14 @@
const { Events, EmbedBuilder } = require('discord.js');
const { client } = require('../index.js');
module.exports = {
name: Events.GuildMemberRemove,
async execute(member) {
const removeMemberEmbed = new EmbedBuilder()
.setTitle(`${member.user.globalName} has left!`)
.setColor(process.env.EMBED_COLOR);
const channel = client.channels.cache.get(process.env.LOG_CHANNEL_ID);
channel.send({ embeds: [removeMemberEmbed] });
},
};

View File

@@ -0,0 +1,25 @@
const { Events } = require('discord.js');
const { simpleEmbed } = require('../functions/embeds.js');
module.exports = {
name: Events.InteractionCreate,
async execute(interaction) {
if (interaction.isChatInputCommand() || interaction.isUserContextMenuCommand()) {
const command = interaction.client.commands.get(interaction.commandName);
if (!command) {
console.error(`No command matching ${interaction.commandName} was found.`);
return;
}
try {
await command.execute(interaction);
} catch (error) {
await interaction.reply({ embeds: [simpleEmbed('There was an error while executing the command')], ephemeral: true });
console.error(`Error executing ${interaction.commandName}`);
console.error(error);
}
}
},
};

View File

@@ -0,0 +1,35 @@
const { Events } = require('discord.js');
const { Users } = require('../functions/models.js');
module.exports = {
name: Events.MessageCreate,
async execute(message) {
if (message.channelId === process.env.MINECRAFT_CHANNEL_ID && !message.author.bot) {
try {
const user = await Users.findOne({ where: { id: message.author.id } });
if (!user) return;
const team = await user.getTeam();
let tellraw;
if (!team) {
tellraw = `tellraw @a ["",{"text":"DC","color":"gray"},{"text":" ${user.rawUsername} > ${message.content}"}]`;
} else {
tellraw = `tellraw @a ["",{"text":"DC ","color":"dark_gray"},{"text":"[","color":"gray"},{"text":"${team.name}","color":"${team.color}"},{"text":"]","color":"gray"},{"text":" ${user.rawUsername} "},{"text":"> ${message.content}"}]`;
}
await fetch(process.env.MINECRAFT_HOST + '/console', {
method: 'POST',
headers: {
'content-type': 'text/plain',
},
body: tellraw,
});
} catch (error) {
console.error(error);
}
}
},
};

View File

@@ -0,0 +1,17 @@
const { Events } = require('discord.js');
const deployCommands = require('../functions/deployCommands');
const { Users, Team, Minecraft } = require('../functions/models');
module.exports = {
name: Events.ClientReady,
once: true,
execute(client) {
Users.sync();
Team.sync();
Minecraft.sync();
console.log(`Ready! Logged in as ${client.user.tag}`);
deployCommands();
},
};

View File

@@ -0,0 +1,45 @@
const { REST, Routes } = require('discord.js');
const fs = require('node:fs');
const path = require('node:path');
module.exports = function deployCommands() {
const commands = [];
const commandsPath = path.join(__dirname, '../commands');
const commandFiles = fs.readdirSync(commandsPath).filter(file => file.endsWith('.js'));
for (const file of commandFiles) {
const filePath = path.join(commandsPath, file);
const command = require(filePath);
if ('data' in command && 'execute' in command) {
commands.push(command.data.toJSON());
} else {
console.log(`[WARNING] The command at ${filePath} is missing a required "data" or "execute" property.`);
}
}
const rest = new REST().setToken(process.env.DISCORD_TOKEN);
(async () => {
try {
console.log(`Started refreshing ${commands.length} application (/) commands.`);
let data;
if (process.env.GUILD_ID === 'production') {
data = await rest.put(
Routes.applicationCommands(process.env.DISCORD_APPLICATION_ID),
{ body: commands },
);
} else {
data = await rest.put(
Routes.applicationGuildCommands(process.env.DISCORD_APPLICATION_ID, process.env.GUILD_ID),
{ body: commands },
);
}
console.log(`Successfully reloaded ${data.length} application (/) commands.`);
} catch (error) {
console.error(error);
}
})();
};

View File

@@ -0,0 +1,9 @@
const { EmbedBuilder } = require('discord.js');
const simpleEmbed = (content) => {
return new EmbedBuilder()
.setColor(process.env.EMBED_COLOR)
.setDescription(content);
};
module.exports = { simpleEmbed };

View File

@@ -0,0 +1,73 @@
const { PartialWebhookMixin } = require('discord.js');
const { sequelize } = require('../index');
const Sequelize = require('sequelize');
const Users = sequelize.define('users', {
id: {
type: Sequelize.STRING,
primaryKey: true,
unique: true,
},
useMinecraftUsername: {
type: Sequelize.BOOLEAN,
defaultValue: false,
},
rawUsername: {
type: Sequelize.STRING,
},
moderator: {
type: Sequelize.BOOLEAN,
defaultValue: false,
},
admin: {
type: Sequelize.BOOLEAN,
defaultValue: false,
},
});
const Team = sequelize.define('teams', {
name: {
type: Sequelize.STRING,
unique: true,
validate: {
len: [3, 16],
isAlphanumeric: true,
},
},
color: {
type: Sequelize.STRING,
validate: {
is: /^#?([A-Fa-f0-9]{6}|[A-Fa-f0-9]{3})$/,
},
},
textChannelId: {
type: Sequelize.STRING,
},
voiceChannelId: {
type: Sequelize.STRING,
},
});
const Minecraft = sequelize.define('minecraft', {
uuid: {
type: Sequelize.UUID,
unique: true,
primaryKey: true,
},
whitelisted: {
type: Sequelize.BOOLEAN,
defaultValue: false,
},
code: {
type: Sequelize.STRING,
unique: true,
},
});
Minecraft.hasOne(Users);
Users.belongsTo(Minecraft);
Team.hasMany(Users, { as: 'members' });
Users.belongsTo(Team);
module.exports = { Users, Team, Minecraft };

View File

@@ -0,0 +1,29 @@
const applyUsername = async (user, member) => {
await user.reload();
let rawUsername = member.user.globalName;
if (user.useMinecraftUsername && user.minecraftUuid) {
const response = await fetch(`https://sessionserver.mojang.com/session/minecraft/profile/${user.minecraftUuid}`);
const minecraftProfile = await response.json();
rawUsername = minecraftProfile.name;
}
user.rawUsername = rawUsername;
const username = await getUsername(user);
await user.save();
await member.setNickname(username.slice(0, 32));
return username;
};
const getUsername = async (user) => {
const team = await user.getTeam();
return team ? user.rawUsername + ' [' + team.name + ']' : user.rawUsername;
};
module.exports = { applyUsername, getUsername };

View File

@@ -1,45 +1,29 @@
const chalk = require('chalk');
const { Client, GatewayIntentBits, Collection } = require('discord.js');
const { Player } = require('discord-player');
const express = require('express');
const Sequelize = require('sequelize');
const dotenv = require('dotenv');
const fs = require('node:fs');
const path = require('node:path');
const dotenv = require('dotenv');
const express = require('express');
const createEmbed = require('./functions/createEmbed.js');
dotenv.config();
const log = {
Info: (message) => console.log(chalk.blue('INFO'), message),
Error: (message) => console.log(chalk.red('ERROR'), message),
Warn: (message) => console.log(chalk.hex('#FFA500'), message),
};
// Register client and music events
const client = new Client({ intents: [GatewayIntentBits.Guilds, GatewayIntentBits.GuildVoiceStates, GatewayIntentBits.GuildMembers, GatewayIntentBits.GuildMessages, GatewayIntentBits.MessageContent] });
client.player = new Player(client);
require('./functions/player.js').registerEvents({ client, createEmbed });
// Express
const app = express();
app.use(express.json());
const minecraftRoute = require('./routes/Minecraft');
const userRoute = require('./routes/User');
const teamRoute = require('./routes/Team');
app.use('/minecraft', minecraftRoute);
app.use('/user', userRoute);
app.use('/team', teamRoute);
app.listen('4000', () => {
log.Info('Express app running');
// Configure database
const sequelize = new Sequelize('polarcraft', 'user', process.env.DATABSE_PASSWORD, {
host: 'localhost',
dialect: 'sqlite',
logging: false,
// SQLite only
storage: 'database.sqlite',
});
exports.sequelize = sequelize;
// Configure Discord
const client = new Client({ intents: [GatewayIntentBits.Guilds, GatewayIntentBits.GuildVoiceStates, GatewayIntentBits.GuildMembers, GatewayIntentBits.GuildMessages, GatewayIntentBits.MessageContent] });
exports.client = client;
// Command handling
client.commands = new Collection();
const commandsPath = path.join(__dirname, 'commands');
@@ -52,12 +36,10 @@ for (const file of commandFiles) {
if ('data' in command && 'execute' in command) {
client.commands.set(command.data.name, command);
} else {
log.Warn(`The command at ${filePath} is missing a required "data" or "execute" property.`);
console.log(`[WARNING] The command at ${filePath} is missing a required "data" or "execute" property.`);
}
}
// Event handling
const eventsPath = path.join(__dirname, 'events');
const eventFiles = fs.readdirSync(eventsPath).filter(file => file.endsWith('.js'));
@@ -65,12 +47,26 @@ for (const file of eventFiles) {
const filePath = path.join(eventsPath, file);
const event = require(filePath);
if (event.once) {
client.once(event.name, (...args) => event.execute({ client, log, createEmbed }, ...args));
client.once(event.name, (...args) => event.execute(...args));
} else {
client.on(event.name, (...args) => event.execute({ client, log, createEmbed }, ...args));
client.on(event.name, (...args) => event.execute(...args));
}
}
// Configure express
const app = express();
app.use(express.json());
const verifyMinecraftRoute = require('./routes/verifyminecraft');
const messageRoute = require('./routes/message');
app.use('/verifyminecraft', verifyMinecraftRoute);
app.use('/message', messageRoute);
app.listen('3000', () => {
console.log('Express app is running');
});
client.login(process.env.DISCORD_TOKEN);
module.exports.client = client;

File diff suppressed because it is too large Load Diff

21
discordbot/package.json Normal file
View File

@@ -0,0 +1,21 @@
{
"name": "discordbot",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"author": "Xeovalyte",
"license": "ISC",
"dependencies": {
"discord.js": "^14.12.1",
"dotenv": "^16.3.1",
"express": "^4.18.2",
"sequelize": "^6.32.1",
"sqlite3": "^5.1.6"
},
"devDependencies": {
"eslint": "^8.46.0"
}
}

View File

@@ -0,0 +1,56 @@
const express = require('express');
const { WebhookClient, EmbedBuilder } = require('discord.js');
const { getUsername } = require('../functions/utils.js');
const { Users } = require('../functions/models.js');
const router = express.Router();
const webhookClient = new WebhookClient({ url: process.env.MINECRAFT_WEBHOOK_URL });
router.post('/player', async (req, res) => {
const { content, uuid } = req.body;
if (!uuid || !content) return res.status(400).send({ errorMessage: 'uuid and content are required' });
try {
const user = await Users.findOne({ where: { minecraftUUID: uuid } });
const username = await getUsername(user);
webhookClient.send({
content,
username,
avatarURL: 'https://api.mineatar.io/face/' + uuid + '?scale=8',
});
res.send({ status: 'ok' });
} catch (error) {
console.log(error);
res.status(500).send({ errorMessage: 'Error while sending player message' });
}
});
router.post('/game', async (req, res) => {
const { content, uuid } = req.body;
if (!uuid || !content) return res.status(400).send({ errorMessage: 'uuid and content are required' });
try {
const messageEmbed = new EmbedBuilder()
.setColor(process.env.EMBED_COLOR)
.setAuthor({ name: content, iconURL: 'https://api.mineatar.io/face/' + uuid + '?scale=8' });
webhookClient.send({
embeds: [messageEmbed],
username: 'Server',
});
res.send({ status: 'ok' });
} catch (error) {
console.log(error);
res.status(500).send({ errorMessage: 'Error while sending player message' });
}
});
module.exports = router;

View File

@@ -0,0 +1,47 @@
const express = require('express');
const { Minecraft, Users } = require('../functions/models.js');
const router = express.Router();
router.post('/', async (req, res) => {
const { uuid } = req.body;
if (!uuid) return res.status(400).send({ errorMessage: 'UUID is required' });
try {
const user = await Users.findOne({ where: { minecraftUUID: uuid } });
if (!user) {
const minecraftCol = await Minecraft.findOrCreate({
where: { uuid },
defaults: {
code: generateCode().toString(),
},
});
return res.send({ code: minecraftCol[0].code, whitelisted: minecraftCol[0].whitelisted });
}
const team = await user.getTeam();
let username;
if (!team) {
username = user.rawUsername;
} else {
username = '<gray>[</gray>' + `<color:${team.color}>${team.name}</color>` + '<gray>] </gray>' + user.rawUsername;
}
res.send({ whitelisted: true, username, rawUsername: user.rawUsername });
} catch (error) {
console.log(error);
res.status(500).send({ errorMessage: 'Error while verifing minecraft uuid' });
}
});
const generateCode = () => {
return Math.floor(100000 + Math.random() * 900000);
};
module.exports = router;

View File

@@ -1,6 +1,7 @@
plugins {
id 'fabric-loom' version '1.1-SNAPSHOT'
id 'fabric-loom' version '1.3-SNAPSHOT'
id 'maven-publish'
id 'com.github.johnrengelman.shadow' version '7.0.0'
}
version = project.mod_version
@@ -42,6 +43,7 @@ dependencies {
// These are included in the Fabric API production distribution and allow you to update your mod to the latest modules at a later more convenient time.
// modImplementation "net.fabricmc.fabric-api:fabric-api-deprecated:${project.fabric_version}"
shadow(implementation("com.sparkjava:spark-core:2.9.4"))
}
processResources {
@@ -72,6 +74,17 @@ jar {
}
}
shadowJar {
configurations = [project.configurations.shadow]
archiveClassifier.set("dev")
relocate "net.objecthunter", "de.siphalor.spiceoffabric.shadow.net.objecthunter"
}
remapJar {
dependsOn(shadowJar)
inputFile = tasks.shadowJar.archiveFile
}
// configure the maven publication
publishing {
publications {
@@ -87,4 +100,4 @@ publishing {
// The repositories here will be used for publishing your artifact, not for
// retrieving dependencies.
}
}
}

View File

@@ -4,9 +4,9 @@ org.gradle.parallel=true
# Fabric Properties
# check these on https://fabricmc.net/develop
minecraft_version=1.19.4
yarn_mappings=1.19.4+build.2
loader_version=0.14.19
minecraft_version=1.20.2
yarn_mappings=1.20.2+build.2
loader_version=0.14.22
# Mod Properties
mod_version=1.0.0
@@ -14,4 +14,4 @@ maven_group=com.xeovalyte.polarcraft
archives_base_name=polarcraft-mod
# Dependencies
fabric_version=0.79.0+1.19.4
fabric_version=0.89.3+1.20.2

View File

@@ -0,0 +1,121 @@
package com.xeovalyte.polarcraft;
import com.xeovalyte.polarcraft.util.messageFunctions;
import com.xeovalyte.polarcraft.util.verifyFunction;
import net.fabricmc.api.ModInitializer;
import org.apache.commons.io.FileUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import net.fabricmc.fabric.api.networking.v1.ServerPlayConnectionEvents;
import net.fabricmc.loader.api.FabricLoader;
import net.minecraft.server.MinecraftServer;
import net.minecraft.server.network.ServerPlayerEntity;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.io.File;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import static spark.Spark.*;
import net.fabricmc.fabric.api.event.lifecycle.v1.ServerLifecycleEvents;
import net.fabricmc.fabric.api.message.v1.ServerMessageEvents;
public class PolarcraftMod implements ModInitializer {
// This logger is used to write text to the console and the log file.
// It is considered best practice to use your mod id as the logger's name.
// That way, it's clear which mod wrote info, warnings, and errors.
public static final Logger LOGGER = LoggerFactory.getLogger("polarcraft-mod");
private static final Gson GSON = new GsonBuilder().setPrettyPrinting().create();
private static final File CONFIG_FILE = new File(FabricLoader.getInstance().getConfigDir().toFile(), "polarcraft.json");
public static String configChatMessageUrl = "https://example.com/message/player";
public static String configGameMessageUrl = "https://example.com/message/game";
public static String configVerifyUrl = "https://example.com/verifyminecraft";
@Override
public void onInitialize() {
// This code runs as soon as Minecraft is in a mod-load-ready state.
// However, some things (like resources) may still be uninitialized.
// Proceed with mild caution.
loadConfig();
ServerPlayConnectionEvents.JOIN.register((handler, sender, server) -> {
ServerPlayerEntity player = (ServerPlayerEntity) handler.player;
verifyFunction.onPlayerJoin(player, server);
});
ServerPlayConnectionEvents.DISCONNECT.register((handler, server) -> {
ServerPlayerEntity player = (ServerPlayerEntity) handler.player;
messageFunctions.sendGameMessage(player.getUuid(), player.getDisplayName().getString() + " left the game");
});
ServerMessageEvents.CHAT_MESSAGE.register((message, sender, params) -> {
messageFunctions.sendChatMessage(message, sender);
});
ServerLifecycleEvents.SERVER_STARTED.register((MinecraftServer server) -> {
port(8080); // Choose a suitable port for your web server
// Define the /console POST endpoint
post("/console", (req, res) -> {
String command = req.body(); // Get the command from the request body
// Validate and sanitize the command if needed
// Execute the console command in the Minecraft environment
executeConsoleCommand(command, server);
res.status(200);
return "Command executed successfully.";
});
});
}
private static void executeConsoleCommand(String command, MinecraftServer server) {
// Code to execute the console command within the Minecraft environment.
server.getCommandManager().executeWithPrefix(server.getCommandSource(), command);
}
private void loadConfig() {
if (!CONFIG_FILE.exists()) {
saveConfig();
return;
}
try {
MyModConfig config = GSON.fromJson(FileUtils.readFileToString(CONFIG_FILE, StandardCharsets.UTF_8), MyModConfig.class);
configChatMessageUrl = config.chatMessageUrl;
configGameMessageUrl = config.gameMessageUrl;
configVerifyUrl = config.verifyUrl;
} catch (IOException e) {
e.printStackTrace();
}
}
private void saveConfig() {
try {
FileUtils.writeStringToFile(CONFIG_FILE, GSON.toJson(new MyModConfig(configChatMessageUrl, configGameMessageUrl, configVerifyUrl)), StandardCharsets.UTF_8);
} catch (IOException e) {
e.printStackTrace();
}
}
public static class MyModConfig {
public String chatMessageUrl;
public String gameMessageUrl;
public String verifyUrl;
public MyModConfig(String chatMessageUrl, String gameMessageUrl,String verifyUrl) {
this.chatMessageUrl = chatMessageUrl;
this.gameMessageUrl = gameMessageUrl;
this.verifyUrl = verifyUrl;
}
}
}

View File

@@ -0,0 +1,27 @@
package com.xeovalyte.polarcraft.mixin;
import com.xeovalyte.polarcraft.util.messageFunctions;
import net.minecraft.entity.damage.DamageSource;
import net.minecraft.server.network.ServerPlayerEntity;
import net.minecraft.text.Text;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
import org.spongepowered.asm.mixin.injection.callback.LocalCapture;
@Mixin(ServerPlayerEntity.class)
public class MixinPlayerEntity {
@Inject(method = "onDeath",
at = @At(
target = "Lnet/minecraft/server/network/ServerPlayNetworkHandler;sendPacket(Lnet/minecraft/network/packet/Packet;Lnet/minecraft/network/PacketCallbacks;)V",
value = "INVOKE",
ordinal = 0),
locals = LocalCapture.CAPTURE_FAILSOFT
)
private void onDeath(DamageSource damageSource, CallbackInfo ci, boolean bl, Text text){
ServerPlayerEntity serverPlayerEntity = (ServerPlayerEntity) (Object) this;
messageFunctions.sendGameMessage(serverPlayerEntity.getUuid(), text.getString());
}
}

View File

@@ -0,0 +1,74 @@
package com.xeovalyte.polarcraft.util;
import com.xeovalyte.polarcraft.PolarcraftMod;
import net.minecraft.network.message.SignedMessage;
import net.minecraft.server.network.ServerPlayerEntity;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.UUID;
public class messageFunctions {
public static void sendGameMessage(UUID uuid, String message) {
try {
// Create a URL object for the server endpoint
URL url = new URL(PolarcraftMod.configGameMessageUrl);
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
connection.setRequestMethod("POST");
connection.setRequestProperty("Content-Type", "application/json");
connection.setDoOutput(true);
String requestBody = "{\"content\":\"" + message + "\", \"uuid\":\"" + uuid + "\"}";
OutputStream outputStream = connection.getOutputStream();
outputStream.write(requestBody.getBytes());
outputStream.flush();
outputStream.close();
BufferedReader reader = new BufferedReader(new InputStreamReader(connection.getInputStream()));
String line;
StringBuilder response = new StringBuilder();
while ((line = reader.readLine()) != null) {
response.append(line);
}
reader.close();
} catch (IOException e) {
e.printStackTrace();
}
}
public static void sendChatMessage( SignedMessage message, ServerPlayerEntity sender) {
try {
// Create a URL object for the server endpoint
URL url = new URL(PolarcraftMod.configChatMessageUrl);
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
connection.setRequestMethod("POST");
connection.setRequestProperty("Content-Type", "application/json");
connection.setDoOutput(true);
String requestBody = "{\"content\":\"" + message.getSignedContent() + "\", \"uuid\":\"" + sender.getUuid() + "\"}";
OutputStream outputStream = connection.getOutputStream();
outputStream.write(requestBody.getBytes());
outputStream.flush();
outputStream.close();
BufferedReader reader = new BufferedReader(new InputStreamReader(connection.getInputStream()));
String line;
StringBuilder response = new StringBuilder();
while ((line = reader.readLine()) != null) {
response.append(line);
}
reader.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}

View File

@@ -0,0 +1,69 @@
package com.xeovalyte.polarcraft.util;
import com.xeovalyte.polarcraft.PolarcraftMod;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.UUID;
import com.google.gson.Gson;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import net.minecraft.server.MinecraftServer;
import net.minecraft.server.network.ServerPlayerEntity;
import net.minecraft.text.Text;
public class verifyFunction {
public static void onPlayerJoin(ServerPlayerEntity player, MinecraftServer server) {
UUID uuid = player.getUuid();
try {
URL url = new URL(PolarcraftMod.configVerifyUrl);
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
connection.setRequestMethod("POST");
connection.setRequestProperty("Content-Type", "application/json");
connection.setDoOutput(true);
String requestBody = "{\"uuid\":\"" + uuid + "\"}";
OutputStream outputStream = connection.getOutputStream();
outputStream.write(requestBody.getBytes());
outputStream.flush();
outputStream.close();
BufferedReader reader = new BufferedReader(new InputStreamReader(connection.getInputStream()));
String line;
StringBuilder response = new StringBuilder();
while ((line = reader.readLine()) != null) {
response.append(line);
}
reader.close();
Gson gson = new Gson();
JsonElement element = gson.fromJson(response.toString(), JsonElement.class);
JsonObject jsonResponse = element.getAsJsonObject();
boolean whitelisted = jsonResponse.get("whitelisted").getAsBoolean();
if (!whitelisted) {
int code = jsonResponse.get("code").getAsInt();
player.networkHandler.disconnect(Text.literal("Whitelist yourself by using the /whitelist command in Discord with this code: " + code));
} else {
server.getCommandManager().executeWithPrefix(server.getCommandSource(), "/lp user " + player.getUuid() + " meta set display " + "\"" + jsonResponse.get("username").getAsString() + "\"");
messageFunctions.sendGameMessage(player.getUuid(), jsonResponse.get("rawUsername").getAsString() + " joined the game");
}
} catch (IOException e) {
player.networkHandler.disconnect(Text.literal("There was an error while verifing your account"));
e.printStackTrace();
}
}
}

View File

@@ -10,6 +10,7 @@ import org.slf4j.LoggerFactory;
import net.fabricmc.fabric.api.networking.v1.ServerPlayConnectionEvents;
import net.fabricmc.loader.api.FabricLoader;
import net.minecraft.server.MinecraftServer;
import net.minecraft.server.network.ServerPlayerEntity;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
@@ -18,6 +19,9 @@ import java.io.File;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import static spark.Spark.*;
import net.fabricmc.fabric.api.event.lifecycle.v1.ServerLifecycleEvents;
import net.fabricmc.fabric.api.message.v1.ServerMessageEvents;
public class PolarcraftMod implements ModInitializer {
@@ -29,9 +33,10 @@ public class PolarcraftMod implements ModInitializer {
private static final Gson GSON = new GsonBuilder().setPrettyPrinting().create();
private static final File CONFIG_FILE = new File(FabricLoader.getInstance().getConfigDir().toFile(), "polarcraft.json");
public static String configChatMessageUrl = "https://example.com/api/minecraft/message/chattodiscord";
public static String configGameMessageUrl = "https://example.com/api/minecraft/message/gametodiscord";
public static String configVerifyUrl = "https://example.com/api/minecraft/verifyuuid";
public static String configChatMessageUrl = "https://example.com/message/player";
public static String configGameMessageUrl = "https://example.com/message/game";
public static String configVerifyUrl = "https://example.com/verifyminecraft";
@Override
public void onInitialize() {
@@ -54,6 +59,28 @@ public class PolarcraftMod implements ModInitializer {
ServerMessageEvents.CHAT_MESSAGE.register((message, sender, params) -> {
messageFunctions.sendChatMessage(message, sender);
});
ServerLifecycleEvents.SERVER_STARTED.register((MinecraftServer server) -> {
port(8080); // Choose a suitable port for your web server
// Define the /console POST endpoint
post("/console", (req, res) -> {
String command = req.body(); // Get the command from the request body
// Validate and sanitize the command if needed
// Execute the console command in the Minecraft environment
executeConsoleCommand(command, server);
res.status(200);
return "Command executed successfully.";
});
});
}
private static void executeConsoleCommand(String command, MinecraftServer server) {
// Code to execute the console command within the Minecraft environment.
server.getCommandManager().executeWithPrefix(server.getCommandSource(), command);
}
private void loadConfig() {
@@ -74,7 +101,7 @@ public class PolarcraftMod implements ModInitializer {
private void saveConfig() {
try {
FileUtils.writeStringToFile(CONFIG_FILE, GSON.toJson(new MyModConfig(configChatMessageUrl, configGameMessageUrl,configVerifyUrl)), StandardCharsets.UTF_8);
FileUtils.writeStringToFile(CONFIG_FILE, GSON.toJson(new MyModConfig(configChatMessageUrl, configGameMessageUrl, configVerifyUrl)), StandardCharsets.UTF_8);
} catch (IOException e) {
e.printStackTrace();
}
@@ -91,4 +118,4 @@ public class PolarcraftMod implements ModInitializer {
this.verifyUrl = verifyUrl;
}
}
}
}

View File

@@ -8,20 +8,15 @@ import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
import org.spongepowered.asm.mixin.injection.callback.LocalCapture;
@Mixin(ServerPlayerEntity.class)
public class MixinPlayerEntity {
@Inject(method = "onDeath",
at = @At(
target = "Lnet/minecraft/server/network/ServerPlayNetworkHandler;sendPacket(Lnet/minecraft/network/packet/Packet;Lnet/minecraft/network/PacketCallbacks;)V",
value = "INVOKE",
ordinal = 0),
locals = LocalCapture.CAPTURE_FAILSOFT
)
private void onDeath(DamageSource damageSource, CallbackInfo ci, boolean bl, Text text){
@Inject(method = "onDeath", at = @At("HEAD"))
private void onDeath(DamageSource damageSource, CallbackInfo ci){
ServerPlayerEntity serverPlayerEntity = (ServerPlayerEntity) (Object) this;
messageFunctions.sendGameMessage(serverPlayerEntity.getUuid(), text.getString());
Text deathMessage = damageSource.getDeathMessage(serverPlayerEntity);
messageFunctions.sendGameMessage(serverPlayerEntity.getUuid(), deathMessage.getString());
}
}

View File

@@ -49,16 +49,16 @@ public class verifyFunction {
JsonElement element = gson.fromJson(response.toString(), JsonElement.class);
JsonObject jsonResponse = element.getAsJsonObject();
boolean verified = jsonResponse.get("verified").getAsBoolean();
boolean whitelisted = jsonResponse.get("whitelisted").getAsBoolean();
if (!verified) {
if (!whitelisted) {
int code = jsonResponse.get("code").getAsInt();
player.networkHandler.disconnect(Text.literal("Whitelist yourself by using this code: " + code));
player.networkHandler.disconnect(Text.literal("Whitelist yourself by using the /whitelist command in Discord with this code: " + code));
} else {
server.getCommandManager().executeWithPrefix(server.getCommandSource(), "/lp user " + player.getUuid() + " meta set display " + "\"" + jsonResponse.get("username").getAsString() + "\"");
messageFunctions.sendGameMessage(player.getUuid(), jsonResponse.get("usernameWithoutStyle").getAsString() + " joined the game");
messageFunctions.sendGameMessage(player.getUuid(), jsonResponse.get("rawUsername").getAsString() + " joined the game");
}
} catch (IOException e) {
player.networkHandler.disconnect(Text.literal("There was an error while verifing your account"));

View File

@@ -24,7 +24,7 @@
],
"depends": {
"fabricloader": ">=0.14.19",
"minecraft": "~1.19.4",
"minecraft": ">=1.20.1",
"java": ">=17",
"fabric-api": "*"
},

View File

@@ -3,7 +3,6 @@
"package": "com.xeovalyte.polarcraft.mixin",
"compatibilityLevel": "JAVA_17",
"mixins": [
"MixinPlayerAdvancementTracker",
"MixinPlayerEntity"
],
"injectors": {

2
modpack-server/.gitattributes vendored Normal file
View File

@@ -0,0 +1,2 @@
# Disable Git line ending conversion, to prevent packwiz index hashes changing when committing from Windows
* -text

5
modpack-server/.gitignore vendored Normal file
View File

@@ -0,0 +1,5 @@
# Exclude exported CurseForge zip files
*.zip
# Exclude exported Modrinth modpacks
*.mrpack

View File

@@ -1,101 +1,171 @@
hash-format = "sha256"
[[files]]
file = "mods/alternate-current.pw.toml"
hash = "fda319290cfe268fdc7c6c6ca8dcad24e51c1de98442f23f2a41d657b26fc8d0"
metafile = true
[[files]]
file = "mods/anti-xray.pw.toml"
hash = "d8833b2961beb076df826ac3a34634260fa9828923a9a327da882065fa3b2f84"
hash = "f0e3f0178d1f8da2487cbb0cea687f441b84109e9f1030e2974d88fe10210aab"
metafile = true
[[files]]
file = "mods/banhammer.pw.toml"
hash = "40a4d80590660eadaa6002f006f0738136fa35583686ea1fb163f98c63d72bac"
hash = "1126dd7cb63d5e4086d74d0fe521156ab9ee0f2d53cd75f3926ffcf256c32953"
metafile = true
[[files]]
file = "mods/c2me-fabric.pw.toml"
hash = "9ab9f1ada10bc693019cdfea96fa09bcbaa3f27c8350e2e23fc45927f838cd9b"
metafile = true
[[files]]
file = "mods/carpet.pw.toml"
hash = "bc125da2af00e14613ca7d6582bbfff0ce63632dac134da4e9cfcf2d724bd856"
metafile = true
[[files]]
file = "mods/chunky.pw.toml"
hash = "c176a0f84b0c3c03423e68b988cd43f51a6b1cf13a844574b19e003324533da0"
metafile = true
[[files]]
file = "mods/debugify.pw.toml"
hash = "d02024521821336e40652c36c675ee520b4137ed73953e98f21bcf8a55f6a583"
hash = "ebc95d8dac761549f43c49938b8d1a0044a43af4484f492959de83a2bdc9e267"
metafile = true
[[files]]
file = "mods/fabric-api.pw.toml"
hash = "e87a52fb14288a8c503c76a40a18fb901de532b2805e84799c63d6202b3ce037"
hash = "d2b04b985ed22bb26338837b0547f08a41b82b23c3136f1fff9582b1748b7954"
metafile = true
[[files]]
file = "mods/fabric-language-kotlin.pw.toml"
hash = "0fe83c99b29c952f464c7bfba9cc86cc4f834bef7834821433fe23ce3dd230e6"
hash = "6f95b9e670d557f852a798489d7b5ec48ed8ddc7e8e1809ff06d4b187d17aac9"
metafile = true
[[files]]
file = "mods/fastback.pw.toml"
hash = "5b7e58e98cafdc851a3f86d9044b8a69a0d719c98fd9a64ab8a492b791861c81"
metafile = true
[[files]]
file = "mods/fastload.pw.toml"
hash = "9ab7092cb7e27bec8bb02d195e8f0c6a207b3f1383da7179a57ebd3328778a24"
hash = "0e72ac12907f4fb5a499a459cc2c64f9225a0c77ee59e76c9360ff0d3479aea2"
metafile = true
[[files]]
file = "mods/ferrite-core.pw.toml"
hash = "4c1b893d87c51588985c483fe33193ca03cf3673de998eef6eeb850d8928e7ab"
hash = "03e174cf691b52da20bd973b955fae6f3720d3d2120f9d6cc1de5fdf3180013c"
metafile = true
[[files]]
file = "mods/headindex.pw.toml"
hash = "48e4d5004d63bf599c62daf73c36f7bfaccd770c7cc8645c2d03e5cddede167d"
file = "mods/forge-config-api-port.pw.toml"
hash = "e00070f0db00ebcd304f8f68fd44e59ceaedbc8c27743c9c195134aae57c5fde"
metafile = true
[[files]]
file = "mods/invview.pw.toml"
hash = "fc6c71feb98476fa7cc0c683a52993bc751772171372fde95b0d823da0c6a2b7"
hash = "9c440b128787446aceeac944eb692793dd24e4596c23d0adfd64a76706ca774d"
metafile = true
[[files]]
file = "mods/krypton.pw.toml"
hash = "f999930809222b57898da25a30aad2135b02894f42c0e1d2832c4670272fbd1d"
metafile = true
[[files]]
file = "mods/lazydfu.pw.toml"
hash = "b4ca05b39b85c27cd97ccb65d5fb832f5e9fd7ee5710542a3e69dfa30a97ea7d"
metafile = true
[[files]]
file = "mods/ledger-databases.pw.toml"
hash = "d8c5d10864c6ee4a5ffdcf775ef6325fb88e6441db9c5c7874be1a6f1d714250"
metafile = true
[[files]]
file = "mods/ledger.pw.toml"
hash = "badf7e1fb371f1cdac13ce547794339a58c64d87793ce4d5bf4151f99d5e2e00"
hash = "e988cb120a107e8d0a3ad501beda973e1b247b290421667a67d95fce146e5dcc"
metafile = true
[[files]]
file = "mods/lithium.pw.toml"
hash = "feaedf6b6d73530c0289d9c7aa4149823343d2a7f9893f7b81e8c7c003763f31"
hash = "ed27ecb297016accc41e9894b6e11d6c46b455211e358afa6218ce629ef56978"
metafile = true
[[files]]
file = "mods/maintenancemode.pw.toml"
hash = "ed2ff97cf59a6c5b9f4e509edbc8c48944bb3c98795f6738c8dfec353cbe350d"
metafile = true
[[files]]
file = "mods/memoryleakfix.pw.toml"
hash = "5b43c0fc6904ad4480c8ed596411c6e24172f8320ccd63de97b4ce2e7e0f90a5"
hash = "8e42842f48b3227733bafced612212eee2298f567ca599ac6a55b9878ae661da"
metafile = true
[[files]]
file = "mods/minimotd.pw.toml"
hash = "c24df3c6860014bab5f2b5998b26a34e93461679b1c22e88c4eebfe992b5d756"
metafile = true
[[files]]
file = "mods/no-chat-reports.pw.toml"
hash = "df11b66e152011f96cc5a4dbf35d2dec99c4373cb19a8c1c761368170d425cf4"
hash = "293f06651cc903947ae422f5e612c73d66154453ad1390bda63920370671b968"
metafile = true
[[files]]
file = "mods/smoothboot-fabric.pw.toml"
hash = "971e8b0bef16bd6ce88c7f940b30fdc1debff7b715058f4d331d54beb58a4314"
file = "mods/ordered-player-list.pw.toml"
hash = "261eb8ac6dcc730afd8643a6486d6b013bbbe2f1200dacc88d7c495e4a588aa5"
metafile = true
[[files]]
file = "mods/pl3xmap.pw.toml"
hash = "53febdce710c35a2c12fe58a55a4d97ee50b0e4cc9ae8bf56e0d436b31602c3b"
metafile = true
[[files]]
file = "mods/servercore.pw.toml"
hash = "17b4cf782db225c145f5c2ababe1042deb0fed021f410d42691829673fa916c3"
metafile = true
[[files]]
file = "mods/slime.pw.toml"
hash = "cbd8c0b34192c5db74644840e2954be757698c805ed95bfb8007253c9783fab0"
metafile = true
[[files]]
file = "mods/spark.pw.toml"
hash = "9f7ce104c709103550148f4ff79acd17f9f93901224166445de1052b681c09da"
hash = "1f922cadccd8b79e824e78d5e2e691e65127e7a500723121a6a6ccc6a1060289"
metafile = true
[[files]]
file = "mods/starlight.pw.toml"
hash = "0a78a506125c0edc97d2292d26c6eab310106c60a5a4e64d73ff67bb619f5a4c"
metafile = true
[[files]]
file = "mods/styled-chat.pw.toml"
hash = "1555d923f1277dfd8c1c55bf1ad8fa109718b717ee2f528fdaa80978e25e74e3"
hash = "06f08304d7ce0221440ece1277be678c17dceb80ff982d19eaa9599345e92328"
metafile = true
[[files]]
file = "mods/styledplayerlist.pw.toml"
hash = "77b0faa9fdcbaf2d0b11358b34a659fd99e00dd5a7f150e0ad69a38259df81a7"
hash = "8a3e2e84597cef453b7f1c46e09764139db8c0915c662c2df9e738bc3efb14b3"
metafile = true
[[files]]
file = "mods/thorium.pw.toml"
hash = "61e2a941621007c901c96fe1474b3c07f208712fa6130151771d5235b6cc8adb"
file = "mods/vanish.pw.toml"
hash = "95886b6bc392072bf3ff366a19dc913745ec24fd86639012c49d50c13ca71cd1"
metafile = true
[[files]]
file = "mods/vmp-fabric.pw.toml"
hash = "4acfdcf28a7214490664892807bdb6c2d73b8d09295677e5629e5c896c3f9fbb"
metafile = true
[[files]]
file = "mods/worldedit.pw.toml"
hash = "a9ef701727ae9dd5baab92af7474cc57e34111b5858941fd5a96c89cacc6a30b"
metafile = true
[[files]]
file = "mods/yacl.pw.toml"
hash = "c66028d555a347562589645179fe8834bd04d48b78c9a667f20b4178211dfbb3"
hash = "46d3f8c4c1bfc8f92858d7e405aed9d1a23e554a783f8977662cbeca06eda5f2"
metafile = true

View File

@@ -1,13 +0,0 @@
name = "Alternate Current"
filename = "alternate-current-mc1.19-1.4.0.jar"
side = "server"
[download]
url = "https://cdn.modrinth.com/data/r0v8vy1s/versions/mc1.19-1.4.0/alternate-current-mc1.19-1.4.0.jar"
hash-format = "sha1"
hash = "108344ed05830948e6ab1414efa4f7ab34e6dba9"
[update]
[update.modrinth]
mod-id = "r0v8vy1s"
version = "4QElEqe4"

View File

@@ -1,13 +1,13 @@
name = "AntiXray"
filename = "anti-xray-1.3.0-Fabric-1.19.3.jar"
filename = "anti-xray-1.3.1-Fabric-1.20.2.jar"
side = "server"
[download]
url = "https://cdn.modrinth.com/data/sml2FMaA/versions/WPaK6kfx/anti-xray-1.3.0-Fabric-1.19.3.jar"
url = "https://cdn.modrinth.com/data/sml2FMaA/versions/asevPA28/anti-xray-1.3.1-Fabric-1.20.2.jar"
hash-format = "sha1"
hash = "a7cdba2fd9a2801cba56e74bedf6c6ee63a461a1"
hash = "9af6c8fe101e9a44500661078386c20cb68c92a4"
[update]
[update.modrinth]
mod-id = "sml2FMaA"
version = "WPaK6kfx"
version = "asevPA28"

View File

@@ -1,13 +1,13 @@
name = "BanHammer"
filename = "banhammer-0.6.3+1.19.3.jar"
filename = "banhammer-0.8.0+1.20.2.jar"
side = "server"
[download]
url = "https://cdn.modrinth.com/data/Wpqg0ciI/versions/LFwC8Fix/banhammer-0.6.3%2B1.19.3.jar"
url = "https://cdn.modrinth.com/data/Wpqg0ciI/versions/Ia1ERLRG/banhammer-0.8.0%2B1.20.2.jar"
hash-format = "sha1"
hash = "8c2bcb4aa5b8aeec6066d96f5675225cb625820a"
hash = "c7e5c4f334063eedad673cee228d35106ff5bfbf"
[update]
[update.modrinth]
mod-id = "Wpqg0ciI"
version = "LFwC8Fix"
version = "Ia1ERLRG"

View File

@@ -0,0 +1,13 @@
name = "Concurrent Chunk Management Engine (Fabric)"
filename = "c2me-fabric-mc1.20.2-0.2.0+alpha.10.126.jar"
side = "both"
[download]
url = "https://cdn.modrinth.com/data/VSNURh3q/versions/ilKwGRiJ/c2me-fabric-mc1.20.2-0.2.0%2Balpha.10.126.jar"
hash-format = "sha1"
hash = "fef69c623f5bfc6c10c86f2790a7c1ac2da3cf32"
[update]
[update.modrinth]
mod-id = "VSNURh3q"
version = "ilKwGRiJ"

View File

@@ -0,0 +1,13 @@
name = "Carpet"
filename = "fabric-carpet-1.20.2-1.4.119+v230928.jar"
side = "both"
[download]
url = "https://cdn.modrinth.com/data/TQTTVgYE/versions/iGHB3B1y/fabric-carpet-1.20.2-1.4.119%2Bv230928.jar"
hash-format = "sha1"
hash = "bfda47816a14ed51f646802ba97ead8e08e4eaa5"
[update]
[update.modrinth]
mod-id = "TQTTVgYE"
version = "iGHB3B1y"

View File

@@ -0,0 +1,13 @@
name = "Chunky"
filename = "Chunky-1.3.92.jar"
side = "both"
[download]
url = "https://cdn.modrinth.com/data/fALzjamp/versions/t8SbUchF/Chunky-1.3.92.jar"
hash-format = "sha1"
hash = "91f8daeeaab0f3114016fb1d45822179701862bf"
[update]
[update.modrinth]
mod-id = "fALzjamp"
version = "t8SbUchF"

View File

@@ -1,13 +1,13 @@
name = "Debugify"
filename = "Debugify-1.19.3+1.1.jar"
filename = "Debugify-1.20.2+1.0.jar"
side = "both"
[download]
url = "https://cdn.modrinth.com/data/QwxR6Gcd/versions/fgjgGIfI/Debugify-1.19.3%2B1.1.jar"
url = "https://cdn.modrinth.com/data/QwxR6Gcd/versions/ZSI78Xd3/Debugify-1.20.2%2B1.0.jar"
hash-format = "sha1"
hash = "d7f9cbf11bb36ef360de2b898a5a5e224eaef9e3"
hash = "5afa015e026de8acb4622e6e1429221e0b26e05e"
[update]
[update.modrinth]
mod-id = "QwxR6Gcd"
version = "fgjgGIfI"
version = "ZSI78Xd3"

View File

@@ -1,13 +1,13 @@
name = "Fabric API"
filename = "fabric-api-0.74.0+1.19.3.jar"
filename = "fabric-api-0.89.3+1.20.2.jar"
side = "both"
[download]
url = "https://cdn.modrinth.com/data/P7dR8mSH/versions/1ld37x4U/fabric-api-0.74.0%2B1.19.3.jar"
url = "https://cdn.modrinth.com/data/P7dR8mSH/versions/Hi8quJUM/fabric-api-0.89.3%2B1.20.2.jar"
hash-format = "sha1"
hash = "119d1710004834d83f34d2b8519aebedba981979"
hash = "de8d59b597ee5bbf1434e495c0cbc3772b1a414a"
[update]
[update.modrinth]
mod-id = "P7dR8mSH"
version = "1ld37x4U"
version = "Hi8quJUM"

View File

@@ -1,13 +1,13 @@
name = "Fabric Language Kotlin"
filename = "fabric-language-kotlin-1.9.1+kotlin.1.8.10.jar"
filename = "fabric-language-kotlin-1.10.10+kotlin.1.9.10.jar"
side = "both"
[download]
url = "https://cdn.modrinth.com/data/Ha28R6CL/versions/lgFl3olb/fabric-language-kotlin-1.9.1%2Bkotlin.1.8.10.jar"
url = "https://cdn.modrinth.com/data/Ha28R6CL/versions/48ri5y9r/fabric-language-kotlin-1.10.10%2Bkotlin.1.9.10.jar"
hash-format = "sha1"
hash = "12f265ea91e73ac2c74c6f66d446671122bbb1c8"
hash = "c708f3f4e94f0f66e72c6e96858368f0512c3b38"
[update]
[update.modrinth]
mod-id = "Ha28R6CL"
version = "lgFl3olb"
version = "48ri5y9r"

View File

@@ -0,0 +1,13 @@
name = "Fast Backups"
filename = "fastback-0.16.1+1.20.2-fabric.jar"
side = "both"
[download]
url = "https://cdn.modrinth.com/data/ZHKrK8Rp/versions/yuRPpkVE/fastback-0.16.1%2B1.20.2-fabric.jar"
hash-format = "sha1"
hash = "13f07b16c9311da033fe38ae93ef34cc0d19c7c4"
[update]
[update.modrinth]
mod-id = "ZHKrK8Rp"
version = "yuRPpkVE"

View File

@@ -1,13 +1,13 @@
name = "Fastload"
filename = "Fastload+1.19.3-2.6.11.jar"
filename = "Fastload+1.18.2-1.20-3.4.0.jar"
side = "both"
[download]
url = "https://cdn.modrinth.com/data/kCpssoSb/versions/GCH0zDV1/Fastload%2B1.19.3-2.6.11.jar"
url = "https://cdn.modrinth.com/data/kCpssoSb/versions/ys9T20o4/Fastload%2B1.18.2-1.20-3.4.0.jar"
hash-format = "sha1"
hash = "a796a3d17378e943a45caf576e9749aaa157d174"
hash = "b57e4d594031638b0dc076a3b6e501f417700577"
[update]
[update.modrinth]
mod-id = "kCpssoSb"
version = "GCH0zDV1"
version = "ys9T20o4"

View File

@@ -1,13 +1,13 @@
name = "FerriteCore"
filename = "ferritecore-5.1.0-fabric.jar"
filename = "ferritecore-6.0.0-fabric.jar"
side = "both"
[download]
url = "https://cdn.modrinth.com/data/uXXizFIs/versions/GHcKib6J/ferritecore-5.1.0-fabric.jar"
url = "https://cdn.modrinth.com/data/uXXizFIs/versions/FCnCG6PS/ferritecore-6.0.0-fabric.jar"
hash-format = "sha1"
hash = "4c45e0e8981374d6c98304c3de90e813eb930673"
hash = "5a57ea73c3c7c0cc300d69611a9cad93baf8e9ab"
[update]
[update.modrinth]
mod-id = "uXXizFIs"
version = "GHcKib6J"
version = "FCnCG6PS"

View File

@@ -0,0 +1,13 @@
name = "Forge Config API Port"
filename = "ForgeConfigAPIPort-v9.0.0-1.20.2-Fabric.jar"
side = "both"
[download]
url = "https://cdn.modrinth.com/data/ohNO6lps/versions/f5d9VI72/ForgeConfigAPIPort-v9.0.0-1.20.2-Fabric.jar"
hash-format = "sha1"
hash = "e9471a5836daab325aaa9bd08759705f8de94545"
[update]
[update.modrinth]
mod-id = "ohNO6lps"
version = "f5d9VI72"

View File

@@ -1,13 +0,0 @@
name = "Head Index"
filename = "headindex-1.1.1.jar"
side = "both"
[download]
url = "https://cdn.modrinth.com/data/mEPmyd7J/versions/smDwseAG/headindex-1.1.1.jar"
hash-format = "sha1"
hash = "0f6ed3d568acd55fcdb4814bdfb4256031254fac"
[update]
[update.modrinth]
mod-id = "mEPmyd7J"
version = "smDwseAG"

View File

@@ -1,13 +1,13 @@
name = "Inv View"
filename = "InvView-1.4.10-1.19.3+.jar"
filename = "InvView-1.4.12-1.20+.jar"
side = "both"
[download]
url = "https://cdn.modrinth.com/data/jrDKjZP7/versions/rv8bhw5X/InvView-1.4.10-1.19.3%2B.jar"
url = "https://cdn.modrinth.com/data/jrDKjZP7/versions/mQnjqDOd/InvView-1.4.12-1.20%2B.jar"
hash-format = "sha1"
hash = "99dd21d6aab9c65d9b1135bce9c912e6bfd48feb"
hash = "f6775526021843c16dc7847bbf0b8dbcca434454"
[update]
[update.modrinth]
mod-id = "jrDKjZP7"
version = "rv8bhw5X"
version = "mQnjqDOd"

View File

@@ -0,0 +1,13 @@
name = "Krypton"
filename = "krypton-0.2.4.jar"
side = "both"
[download]
url = "https://cdn.modrinth.com/data/fQEb0iXm/versions/cQ60Ouax/krypton-0.2.4.jar"
hash-format = "sha1"
hash = "cffdf89a438b83215ddbac2a29c56a2cd68b7d57"
[update]
[update.modrinth]
mod-id = "fQEb0iXm"
version = "cQ60Ouax"

View File

@@ -0,0 +1,13 @@
name = "LazyDFU"
filename = "lazydfu-0.1.3.jar"
side = "both"
[download]
url = "https://cdn.modrinth.com/data/hvFnDODi/versions/0.1.3/lazydfu-0.1.3.jar"
hash-format = "sha1"
hash = "0dfa8b03ed408fb7fdada29e01cfebba02af1049"
[update]
[update.modrinth]
mod-id = "hvFnDODi"
version = "4SHylIO9"

View File

@@ -0,0 +1,13 @@
name = "Ledger Databases"
filename = "ledger-databases-1.1.1.jar"
side = "both"
[download]
hash-format = "sha1"
hash = "d806fed8fea5f3f5a3dc892d605bd6720c86f43e"
mode = "metadata:curseforge"
[update]
[update.curseforge]
file-id = 3834676
project-id = 529404

View File

@@ -1,13 +1,13 @@
name = "Ledger"
filename = "ledger-1.2.6.jar"
filename = "ledger-1.2.9.jar"
side = "server"
[download]
url = "https://cdn.modrinth.com/data/LVN9ygNV/versions/ykSbFGkA/ledger-1.2.6.jar"
url = "https://cdn.modrinth.com/data/LVN9ygNV/versions/8WSkA7qO/ledger-1.2.9.jar"
hash-format = "sha1"
hash = "636857df039d3cec623843844abb72c670590d61"
hash = "8b67c3f918dc655bada6fec3cffcb76628a21a96"
[update]
[update.modrinth]
mod-id = "LVN9ygNV"
version = "ykSbFGkA"
version = "8WSkA7qO"

View File

@@ -1,13 +1,13 @@
name = "Lithium"
filename = "lithium-fabric-mc1.19.3-0.10.4.jar"
filename = "lithium-fabric-mc1.20.2-0.12.0.jar"
side = "both"
[download]
url = "https://cdn.modrinth.com/data/gvQqBUqZ/versions/XS6vJwop/lithium-fabric-mc1.19.3-0.10.4.jar"
url = "https://cdn.modrinth.com/data/gvQqBUqZ/versions/qdzL5Hkg/lithium-fabric-mc1.20.2-0.12.0.jar"
hash-format = "sha1"
hash = "a1b521e18f7857a2fd327c7bebeed3128418e3c9"
hash = "9b713d4909582d900274dcd7ca01abd195b53520"
[update]
[update.modrinth]
mod-id = "gvQqBUqZ"
version = "XS6vJwop"
version = "qdzL5Hkg"

View File

@@ -0,0 +1,13 @@
name = "Maintenance Mode"
filename = "mmode-fabric-1.20-1.1.1.jar"
side = "server"
[download]
url = "https://cdn.modrinth.com/data/QOkEkSap/versions/TT7eUrpf/mmode-fabric-1.20-1.1.1.jar"
hash-format = "sha1"
hash = "da772889aaff617e9d85fd1ff4637663219f38c3"
[update]
[update.modrinth]
mod-id = "QOkEkSap"
version = "TT7eUrpf"

View File

@@ -1,13 +1,13 @@
name = "Memory Leak Fix"
filename = "memoryleakfix-1.19.3-0.7.0.jar"
filename = "memoryleakfix-fabric-1.17+-1.1.2.jar"
side = "both"
[download]
url = "https://cdn.modrinth.com/data/NRjRiSSD/versions/YtNQP5gX/memoryleakfix-1.19.3-0.7.0.jar"
url = "https://cdn.modrinth.com/data/NRjRiSSD/versions/dGlflhb6/memoryleakfix-fabric-1.17%2B-1.1.2.jar"
hash-format = "sha1"
hash = "9fae1093c64b47d6b97ee825ed3d9b725490700c"
hash = "b0eecb140bd124c781469aa0f48bc888072b4ac5"
[update]
[update.modrinth]
mod-id = "NRjRiSSD"
version = "YtNQP5gX"
version = "dGlflhb6"

View File

@@ -0,0 +1,13 @@
name = "MiniMOTD"
filename = "minimotd-fabric-mc1.20.2-2.0.14.jar"
side = "server"
[download]
url = "https://cdn.modrinth.com/data/16vhQOQN/versions/3stGUvKr/minimotd-fabric-mc1.20.2-2.0.14.jar"
hash-format = "sha1"
hash = "060e0cfdcbe2d7fcf35373ec01cf0a3d468dd28b"
[update]
[update.modrinth]
mod-id = "16vhQOQN"
version = "3stGUvKr"

View File

@@ -1,13 +1,13 @@
name = "No Chat Reports"
filename = "NoChatReports-FABRIC-1.19.3-v2.0.0.jar"
filename = "NoChatReports-FABRIC-1.20.2-v2.3.1.jar"
side = "both"
[download]
url = "https://cdn.modrinth.com/data/qQyHxfxd/versions/uVt4LKvF/NoChatReports-FABRIC-1.19.3-v2.0.0.jar"
url = "https://cdn.modrinth.com/data/qQyHxfxd/versions/xQyq2W5g/NoChatReports-FABRIC-1.20.2-v2.3.1.jar"
hash-format = "sha1"
hash = "2eaa80b4480ca6c0d8b1180fdb742ebcb43ac300"
hash = "cb77c14bfc458066eda3c7962c3286e0f973725e"
[update]
[update.modrinth]
mod-id = "qQyHxfxd"
version = "uVt4LKvF"
version = "xQyq2W5g"

View File

@@ -0,0 +1,13 @@
name = "Ordered Player List"
filename = "orderedplayerlist-0.1.3+1.20.2.jar"
side = "server"
[download]
url = "https://cdn.modrinth.com/data/IX99VLW9/versions/DL7rAiJr/orderedplayerlist-0.1.3%2B1.20.2.jar"
hash-format = "sha1"
hash = "2902406910f397bcd8236d51b7b54f9f74c4ba5c"
[update]
[update.modrinth]
mod-id = "IX99VLW9"
version = "DL7rAiJr"

View File

@@ -0,0 +1,13 @@
name = "Pl3xMap"
filename = "Pl3xMap-1.20.2-470.jar"
side = "both"
[download]
url = "https://cdn.modrinth.com/data/YMXhf1UJ/versions/XrSXxwyn/Pl3xMap-1.20.2-470.jar"
hash-format = "sha1"
hash = "1e7b36c914c49f5febd86426ca528556d22479bd"
[update]
[update.modrinth]
mod-id = "YMXhf1UJ"
version = "XrSXxwyn"

View File

@@ -0,0 +1,13 @@
name = "ServerCore"
filename = "servercore-fabric-1.3.8+1.20.2.jar"
side = "both"
[download]
url = "https://cdn.modrinth.com/data/4WWQxlQP/versions/LrB49Mln/servercore-fabric-1.3.8%2B1.20.2.jar"
hash-format = "sha1"
hash = "e99fb454665cd298f44bfb5b415b4b54c02224f9"
[update]
[update.modrinth]
mod-id = "4WWQxlQP"
version = "LrB49Mln"

View File

@@ -0,0 +1,13 @@
name = "Slime"
filename = "slime-1.6.jar"
side = "both"
[download]
url = "https://cdn.modrinth.com/data/qpnMRvwM/versions/sQ9J9gE1/slime-1.6.jar"
hash-format = "sha1"
hash = "ace6e6b4538eaae4e9142023c67b1d5a83928d62"
[update]
[update.modrinth]
mod-id = "qpnMRvwM"
version = "sQ9J9gE1"

View File

@@ -1,13 +0,0 @@
name = "Smooth Boot (Fabric)"
filename = "smoothboot-fabric-1.19-1.7.1.jar"
side = "both"
[download]
url = "https://cdn.modrinth.com/data/FWumhS4T/versions/1.19-1.7.1/smoothboot-fabric-1.19-1.7.1.jar"
hash-format = "sha1"
hash = "8414cbce145a5f48102e6cc811dfd1459afe44f3"
[update]
[update.modrinth]
mod-id = "FWumhS4T"
version = "r8xRVPEI"

View File

@@ -1,13 +1,13 @@
name = "spark"
filename = "spark-1.10.29-fabric.jar"
filename = "spark-1.10.54-fabric.jar"
side = "both"
[download]
url = "https://cdn.modrinth.com/data/l6YH9Als/versions/1K3xO8TS/spark-1.10.29-fabric.jar"
url = "https://cdn.modrinth.com/data/l6YH9Als/versions/tCU9VuzX/spark-1.10.54-fabric.jar"
hash-format = "sha1"
hash = "680b8ed890e05ed0811065a381a7924d536e0508"
hash = "cc6d6dd27e2d6612e848330b5525026709590239"
[update]
[update.modrinth]
mod-id = "l6YH9Als"
version = "1K3xO8TS"
version = "tCU9VuzX"

View File

@@ -0,0 +1,13 @@
name = "Starlight (Fabric)"
filename = "starlight-1.1.2+fabric.bdaeb21.jar"
side = "both"
[download]
url = "https://cdn.modrinth.com/data/H8CaAYZC/versions/98VOoYPX/starlight-1.1.2%2Bfabric.bdaeb21.jar"
hash-format = "sha1"
hash = "6cf71105561a6893f76ae561fdbef839c404b8b5"
[update]
[update.modrinth]
mod-id = "H8CaAYZC"
version = "98VOoYPX"

View File

@@ -1,13 +1,13 @@
name = "Styled Chat"
filename = "styled-chat-2.1.2+1.19.3.jar"
filename = "styled-chat-2.3.0+1.20.2.jar"
side = "both"
[download]
url = "https://cdn.modrinth.com/data/doqSKB0e/versions/BriPIjGV/styled-chat-2.1.2%2B1.19.3.jar"
url = "https://cdn.modrinth.com/data/doqSKB0e/versions/J9nCzhiG/styled-chat-2.3.0%2B1.20.2.jar"
hash-format = "sha1"
hash = "f54c649adb0b4cfccdfca71ddd0a2f4afe761947"
hash = "a6401354c9d393914930556827abe01e090d33df"
[update]
[update.modrinth]
mod-id = "doqSKB0e"
version = "BriPIjGV"
version = "J9nCzhiG"

View File

@@ -1,13 +1,13 @@
name = "Styled Player List"
filename = "styledplayerlist-2.3.0+1.19.3.jar"
side = "server"
filename = "styledplayerlist-3.2.0+1.20.2.jar"
side = "both"
[download]
url = "https://cdn.modrinth.com/data/DQIfKUHf/versions/cEi0Qx95/styledplayerlist-2.3.0%2B1.19.3.jar"
url = "https://cdn.modrinth.com/data/DQIfKUHf/versions/8c1ZipKd/styledplayerlist-3.2.0%2B1.20.2.jar"
hash-format = "sha1"
hash = "1edd1c021991f26ab42ea3eb49153d719153a582"
hash = "82895d8776b10b927e503c3f79ece0d8a12eb839"
[update]
[update.modrinth]
mod-id = "DQIfKUHf"
version = "cEi0Qx95"
version = "8c1ZipKd"

View File

@@ -1,13 +0,0 @@
name = "thorium"
filename = "thorium-1.4.0.jar"
side = "both"
[download]
url = "https://cdn.modrinth.com/data/ImUQFWcy/versions/ChzyZR8C/thorium-1.4.0.jar"
hash-format = "sha1"
hash = "dc5d3176cf60ee669ef0f5ca0fc151cd403aa64a"
[update]
[update.modrinth]
mod-id = "ImUQFWcy"
version = "ChzyZR8C"

View File

@@ -0,0 +1,13 @@
name = "Vanish"
filename = "vanish-1.4.2+1.20.2.jar"
side = "server"
[download]
url = "https://cdn.modrinth.com/data/UL4bJFDY/versions/hqxpO8Cn/vanish-1.4.2%2B1.20.2.jar"
hash-format = "sha1"
hash = "cfa3fc2cdebb3fd4c88fa0b691651c797dc1ddf6"
[update]
[update.modrinth]
mod-id = "UL4bJFDY"
version = "hqxpO8Cn"

View File

@@ -0,0 +1,13 @@
name = "Very Many Players (Fabric)"
filename = "vmp-fabric-mc1.20.2-0.2.0+beta.7.115-all.jar"
side = "both"
[download]
url = "https://cdn.modrinth.com/data/wnEe9KBa/versions/XHRLuI9m/vmp-fabric-mc1.20.2-0.2.0%2Bbeta.7.115-all.jar"
hash-format = "sha1"
hash = "39322ddb12deb6c59599109733adc6435fe12ef7"
[update]
[update.modrinth]
mod-id = "wnEe9KBa"
version = "XHRLuI9m"

View File

@@ -0,0 +1,13 @@
name = "WorldEdit"
filename = "worldedit-mod-7.2.16.jar"
side = "both"
[download]
hash-format = "sha1"
hash = "6c55c44d4fa4b681c5c8d8159c33ff05c46b92d2"
mode = "metadata:curseforge"
[update]
[update.curseforge]
file-id = 4773938
project-id = 225608

Some files were not shown because too many files have changed in this diff Show More