Skip to content

Commit

Permalink
Merge pull request #3 from skuzow/develop
Browse files Browse the repository at this point in the history
v0.0.1
  • Loading branch information
skuzow authored Jun 26, 2022
2 parents e82b62d + c3d7ccd commit 0f9f920
Show file tree
Hide file tree
Showing 8 changed files with 342 additions and 0 deletions.
37 changes: 37 additions & 0 deletions .github/workflows/package.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
name: package
on: push

jobs:
build:
strategy:
matrix:
# Use these Python versions
python: [
3.6
]
# and run on both Linux and Windows
os: [ ubuntu-20.04, windows-2022 ]
runs-on: ${{ matrix.os }}
steps:
- uses: actions/checkout@v2
- name: Setup python
uses: actions/setup-python@v2
with:
python-version: ${{ matrix.python }}
- uses: actions/cache@v2
with:
path: ~/.cache/pip
key: ${{ matrix.os }}-pip-${{ hashFiles('**/requirements.txt') }}
restore-keys: |
${{ matrix.os }}-pip-
- name: Install dependencies
run: |
python -m pip install --upgrade pip
pip install -r requirements.txt
- name: Pack Plugin
run: |
python -m mcdreforged pack -o ./package
- uses: actions/upload-artifact@v2
with:
name: CI Auto build for ${{ github.sha }}
path: package/
136 changes: 136 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,136 @@
# Byte-compiled / optimized / DLL files
__pycache__/
*.py[cod]
*$py.class

# C extensions
*.so

# Distribution / packaging
.Python
build/
develop-eggs/
dist/
downloads/
eggs/
.eggs/
lib/
lib64/
parts/
sdist/
var/
wheels/
pip-wheel-metadata/
share/python-wheels/
*.egg-info/
.installed.cfg
*.egg
MANIFEST

# PyInstaller
# Usually these files are written by a python script from a template
# before PyInstaller builds the exe, so as to inject date/other infos into it.
*.manifest
*.spec

# Installer logs
pip-log.txt
pip-delete-this-directory.txt

# Unit test / coverage reports
htmlcov/
.tox/
.nox/
.coverage
.coverage.*
.cache
nosetests.xml
coverage.xml
*.cover
*.py,cover
.hypothesis/
.pytest_cache/

# Translations
*.mo
*.pot

# Django stuff:
*.log
local_settings.py
db.sqlite3
db.sqlite3-journal

# Flask stuff:
instance/
.webassets-cache

# Scrapy stuff:
.scrapy

# Sphinx documentation
docs/_build/

# PyBuilder
target/

# Jupyter Notebook
.ipynb_checkpoints

# IPython
profile_default/
ipython_config.py

# pyenv
.python-version

# pipenv
# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
# However, in case of collaboration, if having platform-specific dependencies or dependencies
# having no cross-platform support, pipenv may install dependencies that don't work, or not
# install all needed dependencies.
#Pipfile.lock

# PEP 582; used by e.g. github.com/David-OConnor/pyflow
__pypackages__/

# Celery stuff
celerybeat-schedule
celerybeat.pid

# SageMath parsed files
*.sage.py

# Environments
.env
.venv
env/
venv/
ENV/
env.bak/
venv.bak/

# Spyder project settings
.spyderproject
.spyproject

# Rope project settings
.ropeproject

# mkdocs documentation
/site

# mypy
.mypy_cache/
.dmypy.json
dmypy.json

# Pyre type checker
.pyre/

# IDE
/.idea/

# MCDR
*.mcdr
*.pyz
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
# 📃 Offline Whitelist

[![license](https://img.shields.io/github/license/skuzow/offline-whitelist.svg)](https://github.com/skuzow/offline-whitelist/blob/master/LICENSE)
[![package](https://github.com/skuzow/offline-whitelist/actions/workflows/package.yml/badge.svg?branch=master)](https://github.com/skuzow/offline-whitelist/actions/workflows/package.yml)
[![python versions](https://img.shields.io/badge/python->=%203.6%20-blue)](https://www.python.org/downloads)

Simple [MCDReforged](https://github.com/Fallen-Breath/MCDReforged) offline whitelist helper plugin.

Expand Down
14 changes: 14 additions & 0 deletions mcdreforged.plugin.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
{
"id": "offline_whitelist",
"version": "0.0.1",
"name": "OfflineWhitelist",
"description": "Offline whitelist helper",
"author": "skuzow",
"link": "https://github.com/skuzow/offline-whitelist",
"dependencies": {
"mcdreforged": ">=2.1.0"
},
"resources": [
"LICENSE"
]
}
31 changes: 31 additions & 0 deletions offline_whitelist/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
from mcdreforged.api.all import *
from offline_whitelist.commands import whitelist_add
from offline_whitelist.utils import load_config

PLUGIN_METADATA = ServerInterface.get_instance().as_plugin_server_interface().get_self_metadata()


prefix = '!!offw'
description = PLUGIN_METADATA.description
help_message = '''
--- MCDR {1} v{2} ---
- {3} plugin
{0} add §6[username] §rAdd offline player to whitelist
'''.strip().format(prefix, PLUGIN_METADATA.name, PLUGIN_METADATA.version, description)


def on_load(server: PluginServerInterface, old):
load_config(None, server)
server.register_help_message(prefix, description)
register_commands(server)


def register_commands(server: PluginServerInterface):
def get_username(callback):
return Text('username').runs(callback)
server.register_command(
Literal(prefix).
runs(lambda src: src.reply(help_message)).
on_error(UnknownArgument, lambda src: src.reply(f'Parameter error! Please enter §7{prefix}§r to get plugin help'), handled=True).
then(Literal('add').then(get_username(lambda src, ctx: whitelist_add(src, ctx['username']))))
)
28 changes: 28 additions & 0 deletions offline_whitelist/commands.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import time

from mcdreforged.api.all import *
from offline_whitelist.utils import get_config, find_file, generate_offline, load_file, dump_file, send_info, \
send_error, check_permission


def whitelist_add(source: CommandSource, username):
config = get_config()
if find_file(source, config.whitelist_path) and check_permission(source, 3):
source.get_server().execute(f'whitelist add {username}')
time.sleep(0.5)
offline_uuid = generate_offline(source, username)
whitelist_json = load_file(source, config.whitelist_path)
# search player username inside whitelist & change uuid to offline one
for player in whitelist_json:
if player["name"] == username:
if not player["uuid"] == offline_uuid:
player["uuid"] = offline_uuid
dump_file(source, config.whitelist_path, whitelist_json)
source.get_server().execute('whitelist reload')
return send_info(source, f'Successfully added to whitelist: {username}')
else:
return send_error(source, f'Player already whitelisted: {username}', None)
# couldn't find nickname because bad written / only for online players
send_error(source, f'Username is misspelled: {username}', None)
source.get_server().execute(f'whitelist remove {username}')
source.get_server().execute('whitelist reload')
93 changes: 93 additions & 0 deletions offline_whitelist/utils.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
import hashlib
import json
import os
from typing import Optional

from mcdreforged.api.all import *

PLUGIN_METADATA = ServerInterface.get_instance().as_plugin_server_interface().get_self_metadata()


class Config(Serializable):
whitelist_path: str = './server/whitelist.json'


config: Optional[Config] = None


def generate_offline(source: CommandSource, username):
# extracted from the java code:
# new GameProfile(UUID.nameUUIDFromBytes(("OfflinePlayer:" + name).getBytes(Charsets.UTF_8)), name));
string = "OfflinePlayer:" + username
hash = hashlib.md5(string.encode('utf-8')).digest()
byte_array = [byte for byte in hash]
byte_array[6] = hash[6] & 0x0f | 0x30
byte_array[8] = hash[8] & 0x3f | 0x80
offline_uuid = __add_stripes(bytes(byte_array).hex())
source.get_server().logger.info(f'Username converted: {username} -> uuid: {offline_uuid}')
return offline_uuid


def __add_stripes(uuid):
return uuid[:8] + '-' + uuid[8:12] + '-' + uuid[12:16] + '-' + uuid[16:20] + '-' + uuid[20:]


def check_permission(source: CommandSource, min_permission_level):
if source.has_permission_higher_than(min_permission_level - 1):
return True
else:
source.reply('You don\'t permission to run this command')
return False


def load_config(source: Optional[CommandSource], server: PluginServerInterface):
global config
config_file_path = os.path.join('config', '{}.json'.format(PLUGIN_METADATA.id))
config = server.load_config_simple(config_file_path, in_data_folder=False, source_to_reply=source,
echo_in_console=False, target_class=Config)


def get_config():
return config


def send_info(source: CommandSource, message):
source.reply(message)
source.get_server().logger.info(message)


def send_error(source: CommandSource, message, error):
source.reply(message)
source.get_server().logger.error(message)
if error is not None:
source.get_server().logger.error(error)


def find_file(source: CommandSource, file_path):
# check if file with path given exists
if os.path.isfile(file_path):
return True
send_error(source, f'Couldn\'t found file: {config.whitelist_path}', None)
return False


def load_file(source: CommandSource, file_path):
try:
# open, load & close file in read mode
read_file = open(file_path, 'r')
file_json = json.load(read_file)
read_file.close()
return file_json
except Exception as error:
send_error(source, f'Couldn\'t load file: {file_path}', error)


def dump_file(source: CommandSource, file_path, file_json):
try:
# open file in write mode
write_file = open(file_path, 'w')
# save changes into the file in the disk, then closes it
json.dump(file_json, write_file, indent=2)
source.get_server().execute('whitelist reload')
except Exception as error:
send_error(source, f'Couldn\'t dump file: {file_path}', error)
1 change: 1 addition & 0 deletions requirements.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
mcdreforged>=2.1.0

0 comments on commit 0f9f920

Please sign in to comment.