mirror of
https://github.com/WiIIiam278/HuskSync.git
synced 2025-12-19 06:49:17 +00:00
test: improve test suite
use velocity instead of Waterfall add some basic docs include the default test config
This commit is contained in:
3
.gitignore
vendored
3
.gitignore
vendored
@@ -121,5 +121,4 @@ run/
|
||||
|
||||
# Don't include generated test suite files
|
||||
/test/servers/
|
||||
/test/HuskSync
|
||||
/test/config.yml
|
||||
/test/HuskSync
|
||||
29
test/README.md
Normal file
29
test/README.md
Normal file
@@ -0,0 +1,29 @@
|
||||
# Testing HuskSync
|
||||
This is a rudimentary Python script for running a little Proxy network of servers for quickly testing HuskSync.
|
||||
|
||||
Run the script to spin up a Velocity proxy and a pair of Paper servers for testing HuskSync.
|
||||
|
||||
* Useful for development & feature testing
|
||||
* Not useful for stress or integration testing.
|
||||
* Only works on Windows (as it deals with bash scripts)
|
||||
* Only spins up Paper servers at the moment ()
|
||||
|
||||
If you don't want to do this you can also run a single-server test with the various `runServer` tasks in the Bukkit/Fabric modules.
|
||||
|
||||
_PRs to improve testing are welcomed with open arms & cups of tea!_
|
||||
|
||||
## Requirements
|
||||
* Windows
|
||||
* Python 3.14
|
||||
* MySQL DB running locally
|
||||
* Redis running locally
|
||||
|
||||
## How to run
|
||||
1. Edit `spin_network.py` to your liking (change the MC version, add your name/UUID as a server operator)
|
||||
2. Configure HuskSync to point to your local MySQL/Redis DB (edit `~/test/config.yml`)
|
||||
3. Run `pip install -r requirements.txt
|
||||
4. From the repository route, open terminal and run `cd ./test`, then `python3 ./spin_network.py`
|
||||
|
||||
## Tips
|
||||
* Delete `~/test/servers` and `~/test/HuskSync` each time you want to download Paper/Velocity & re-create worlds, etc.
|
||||
* Create an IntelliJ Run & Debug Python task to do this with a `Run Gradle Task before` to `clean build` the project before.
|
||||
184
test/config.yml
Normal file
184
test/config.yml
Normal file
@@ -0,0 +1,184 @@
|
||||
# Locale of the default language file to use.
|
||||
# Docs: https://william278.net/docs/husksync/translations
|
||||
language: en-gb
|
||||
|
||||
# Whether to automatically check for plugin updates on startup
|
||||
check_for_updates: false
|
||||
|
||||
# Specify a common ID for grouping servers running HuskSync. Don't modify this unless you know what you're doing!
|
||||
cluster_id: ''
|
||||
|
||||
# Enable development debug logging
|
||||
debug_logging: false
|
||||
|
||||
# Whether to enable the Player Analytics hook.
|
||||
# Docs: https://william278.net/docs/husksync/plan-hook
|
||||
enable_plan_hook: true
|
||||
|
||||
# Whether to cancel game event packets directly when handling locked players if ProtocolLib or PacketEvents is installed
|
||||
cancel_packets: true
|
||||
|
||||
# Add HuskSync commands to this list to prevent them from being registered (e.g. ['userdata'])
|
||||
disabled_commands: []
|
||||
|
||||
# Database settings
|
||||
database:
|
||||
|
||||
# Type of database to use (MYSQL, MARIADB, POSTGRES, MONGO)
|
||||
type: MARIADB
|
||||
|
||||
# Specify credentials here for your MYSQL, MARIADB, POSTGRES OR MONGO database
|
||||
credentials:
|
||||
host: localhost
|
||||
port: 3306
|
||||
database: plugin_testing
|
||||
username: root
|
||||
password: ''
|
||||
|
||||
# Only change this if you're using MARIADB or POSTGRES
|
||||
parameters: ?autoReconnect=true&useSSL=false&useUnicode=true&characterEncoding=UTF-8
|
||||
|
||||
# MYSQL, MARIADB, POSTGRES database Hikari connection pool properties. Don't modify this unless you know what you're doing!
|
||||
connection_pool:
|
||||
maximum_pool_size: 10
|
||||
minimum_idle: 10
|
||||
maximum_lifetime: 1800000
|
||||
keepalive_time: 0
|
||||
connection_timeout: 5000
|
||||
|
||||
# Advanced MongoDB settings. Don't modify unless you know what you're doing!
|
||||
mongo_settings:
|
||||
using_atlas: false
|
||||
parameters: ?retryWrites=true&w=majority&authSource=HuskSync
|
||||
|
||||
# Names of tables to use on your database. Don't modify this unless you know what you're doing!
|
||||
table_names:
|
||||
users: husksync_users
|
||||
user_data: husksync_user_data
|
||||
|
||||
# Whether to run the creation SQL on the database when the server starts. Don't modify this unless you know what you're doing!
|
||||
create_tables: true
|
||||
|
||||
# Redis settings
|
||||
redis:
|
||||
|
||||
# Specify the credentials of your Redis server here. Set "password" to '' if you don't have one
|
||||
credentials:
|
||||
host: localhost
|
||||
port: 6379
|
||||
password: ''
|
||||
use_ssl: false
|
||||
|
||||
# Options for if you're using Redis sentinel. Don't modify this unless you know what you're doing!
|
||||
sentinel:
|
||||
|
||||
# The master set name for the Redis sentinel.
|
||||
master: ''
|
||||
|
||||
# List of host:port pairs
|
||||
nodes: []
|
||||
password: ''
|
||||
|
||||
# Data syncing settings
|
||||
synchronization:
|
||||
|
||||
# The data synchronization mode to use (LOCKSTEP or DELAY). LOCKSTEP is recommended for most networks.
|
||||
# Docs: https://william278.net/docs/husksync/sync-modes
|
||||
mode: LOCKSTEP
|
||||
|
||||
# The number of data snapshot backups that should be kept at once per user
|
||||
max_user_data_snapshots: 16
|
||||
|
||||
# Number of hours between new snapshots being saved as backups (Use "0" to backup all snapshots)
|
||||
snapshot_backup_frequency: 4
|
||||
|
||||
# List of save cause IDs for which a snapshot will be automatically pinned (so it won't be rotated).
|
||||
# Docs: https://william278.net/docs/husksync/data-rotation#save-causes
|
||||
auto_pinned_save_causes:
|
||||
- INVENTORY_COMMAND
|
||||
- ENDERCHEST_COMMAND
|
||||
- BACKUP_RESTORE
|
||||
- LEGACY_MIGRATION
|
||||
- MPDB_MIGRATION
|
||||
|
||||
# Whether to create a snapshot for users on a world when the server saves that world
|
||||
save_on_world_save: true
|
||||
|
||||
# Configuration for how and when to sync player data when they die
|
||||
save_on_death:
|
||||
|
||||
# Whether to create a snapshot for users when they die (containing their death drops)
|
||||
enabled: false
|
||||
|
||||
# What items to save in death snapshots? (DROPS or ITEMS_TO_KEEP). Note that ITEMS_TO_KEEP (suggested for keepInventory servers) requires a Paper 1.19.4+ server.
|
||||
items_to_save: DROPS
|
||||
|
||||
# Should a death snapshot still be created even if the items to save on the player's death are empty?
|
||||
save_empty_items: true
|
||||
|
||||
# Whether dead players who log out and log in to a different server should have their items saved.
|
||||
sync_dead_players_changing_server: true
|
||||
|
||||
# Whether to use the snappy data compression algorithm. Keep on unless you know what you're doing
|
||||
compress_data: true
|
||||
|
||||
# Where to display sync notifications (ACTION_BAR, CHAT or NONE)
|
||||
notification_display_slot: ACTION_BAR
|
||||
|
||||
# Persist maps locked in a Cartography Table to let them be viewed on any server
|
||||
persist_locked_maps: true
|
||||
|
||||
# If using the DELAY sync method, how long should this server listen for Redis key data updates before pulling data from the database instead (i.e., if the user did not change servers).
|
||||
network_latency_milliseconds: 500
|
||||
|
||||
# Which data types to synchronize.
|
||||
# Docs: https://william278.net/docs/husksync/sync-features
|
||||
features:
|
||||
experience: true
|
||||
potion_effects: true
|
||||
flight_status: true
|
||||
ender_chest: true
|
||||
location: false
|
||||
attributes: true
|
||||
advancements: true
|
||||
game_mode: true
|
||||
persistent_data: true
|
||||
inventory: true
|
||||
hunger: true
|
||||
statistics: true
|
||||
health: true
|
||||
|
||||
# Commands which should be blocked before a player has finished syncing (Use * to block all commands)
|
||||
blacklisted_commands_while_locked:
|
||||
- '*'
|
||||
|
||||
# Configuration for how to sync attributes
|
||||
attributes:
|
||||
|
||||
# Which attribute types should be saved as part of attribute syncing. Supports wildcard matching.
|
||||
# (e.g. ['minecraft:generic.max_health', 'minecraft:generic.*'])
|
||||
synced_attributes:
|
||||
- minecraft:generic.max_health
|
||||
- minecraft:max_health
|
||||
- minecraft:generic.max_absorption
|
||||
- minecraft:max_absorption
|
||||
- minecraft:generic.luck
|
||||
- minecraft:luck
|
||||
- minecraft:generic.scale
|
||||
- minecraft:scale
|
||||
- minecraft:generic.step_height
|
||||
- minecraft:step_height
|
||||
- minecraft:generic.gravity
|
||||
- minecraft:gravity
|
||||
|
||||
# Which attribute modifiers should be saved. Supports wildcard matching.
|
||||
# (e.g. ['minecraft:effect.speed', 'minecraft:effect.*'])
|
||||
ignored_modifiers:
|
||||
- minecraft:effect.*
|
||||
- minecraft:creative_mode_*
|
||||
|
||||
# Event priorities for listeners (HIGHEST, NORMAL, LOWEST). Change if you encounter plugin conflicts
|
||||
event_priorities:
|
||||
quit_listener: LOWEST
|
||||
join_listener: LOWEST
|
||||
death_listener: NORMAL
|
||||
@@ -12,7 +12,7 @@ from tqdm import tqdm
|
||||
# Parameters for starting a network of Minecraft servers
|
||||
class Parameters:
|
||||
root_dir = './servers/'
|
||||
proxy_version = "1.21"
|
||||
proxy_version = "3.4.0-SNAPSHOT"
|
||||
minecraft_version = '1.21.4'
|
||||
eula_agreement = 'true'
|
||||
|
||||
@@ -20,7 +20,7 @@ class Parameters:
|
||||
backend_ports = [25567, 25568]
|
||||
backend_type = 'paper'
|
||||
backend_ram = 2048
|
||||
backend_plugins = ['../target/HuskSync-Paper-*.jar']
|
||||
backend_plugins = ['../target/HuskSync-Bukkit-*.jar']
|
||||
backend_plugin_folders = ['./HuskSync']
|
||||
operator_names = ['William278']
|
||||
operator_uuids = ['5dfb0558-e306-44f4-bb9a-f9218d4eb787']
|
||||
@@ -28,11 +28,13 @@ class Parameters:
|
||||
proxy_name = "proxy"
|
||||
proxy_host = "0.0.0.0"
|
||||
proxy_port = 25565
|
||||
proxy_type = "waterfall"
|
||||
proxy_type = "velocity"
|
||||
proxy_ram = 512
|
||||
proxy_plugins = []
|
||||
proxy_plugin_folders = []
|
||||
|
||||
velocity_secret = "qUTwFSVeQqhH" # Doesn't matter that this is committed or anything, it's just for testing
|
||||
|
||||
just_update_plugins = False
|
||||
|
||||
|
||||
@@ -59,7 +61,7 @@ def main(update=False):
|
||||
os.makedirs(plugin_dir)
|
||||
|
||||
# Copy plugins in
|
||||
copy_plugins(parameters.backend_plugins, parameters.backend_plugin_folders, plugin_dir)
|
||||
copy_plugins(parameters.backend_plugins, parameters.backend_plugin_folders, plugin_dir, parameters)
|
||||
|
||||
# Start servers
|
||||
start_servers(parameters)
|
||||
@@ -114,14 +116,16 @@ def create_backend_server(name, port, parameters):
|
||||
with open(server_dir + "/spigot.yml", "w") as file:
|
||||
file.write(f"# Auto-generated spigot.yml for server {name}\n")
|
||||
file.write(f"settings:\n")
|
||||
file.write(f" bungeecord: true\n")
|
||||
file.write(f" bungeecord: false\n")
|
||||
|
||||
# Create the paper-global.yml and enable BungeeCord
|
||||
with open(server_dir + "/config/paper-global.yml", "w") as file:
|
||||
file.write(f"# Auto-generated paper-global.yml for server {name}\n")
|
||||
file.write(f"proxies:\n")
|
||||
file.write(f" bungee-cord:\n")
|
||||
file.write(f" velocity:\n")
|
||||
file.write(f" enabled: true\n")
|
||||
file.write(f" online-mode: true\n")
|
||||
file.write(f" secret: {parameters.velocity_secret}\n")
|
||||
|
||||
# Create the server.properties file
|
||||
server_properties = server_dir + "/server.properties"
|
||||
@@ -153,7 +157,7 @@ def create_backend_server(name, port, parameters):
|
||||
file.write("]")
|
||||
|
||||
# Copy plugins
|
||||
copy_plugins(parameters.backend_plugins, parameters.backend_plugin_folders, f"{server_dir}/plugins")
|
||||
copy_plugins(parameters.backend_plugins, parameters.backend_plugin_folders, f"{server_dir}/plugins", parameters)
|
||||
|
||||
# Create start scripts
|
||||
create_start_scripts(server_dir,
|
||||
@@ -169,44 +173,74 @@ def create_proxy_server(parameters):
|
||||
if not os.path.exists(server_dir):
|
||||
os.makedirs(server_dir)
|
||||
|
||||
if parameters.proxy_type == "waterfall":
|
||||
if parameters.proxy_type == "velocity":
|
||||
# Create necessary subdirectories
|
||||
create_subdirectories(["plugins"], server_dir)
|
||||
|
||||
# Download the latest paper for the version and place it in the server folder
|
||||
proxy_jar = "waterfall.jar"
|
||||
download_paper_build("waterfall", parameters.proxy_version,
|
||||
get_latest_paper_build_number("waterfall", parameters.proxy_version),
|
||||
proxy_jar = "velocity.jar"
|
||||
download_paper_build("velocity", parameters.proxy_version,
|
||||
get_latest_paper_build_number("velocity", parameters.proxy_version),
|
||||
f"{server_dir}/{proxy_jar}")
|
||||
|
||||
# Create the config.yml
|
||||
with open(server_dir + "/config.yml", "w") as file:
|
||||
file.write(f"# Auto-generated config.yml for proxy server {parameters.proxy_name}\n")
|
||||
# Create the forwarding.secret
|
||||
with open(server_dir + "/forwarding.secret", "w") as file:
|
||||
file.write(f"{parameters.velocity_secret}\n")
|
||||
|
||||
# Create the velocity.toml
|
||||
with open(server_dir + "/velocity.toml", "w") as file:
|
||||
file.write(f"# Auto-generated velocity.toml for proxy server {parameters.proxy_name}\n")
|
||||
|
||||
# Write proxy settings
|
||||
file.write(f"listeners:\n")
|
||||
file.write(f"- query_port: {parameters.proxy_port}\n")
|
||||
file.write(f" motd: '{parameters.proxy_version} Proxy Server'\n")
|
||||
file.write(f" query_enabled: false\n")
|
||||
file.write(f" proxy_protocol: false\n")
|
||||
file.write(f" priorities:\n")
|
||||
file.write(f" - {parameters.backend_names[0]}\n")
|
||||
file.write(f" bind_local_address: true\n")
|
||||
file.write(f" host: {parameters.proxy_host}:{parameters.proxy_port}\n")
|
||||
file.write(f"ip_forward: true\n")
|
||||
file.write(f"online_mode: true\n")
|
||||
file.write(f"config-version = '2.6'\n")
|
||||
file.write(f"bind = '0.0.0.0:{parameters.proxy_port}'\n")
|
||||
file.write(f"motd = \"Velocity Proxy Server\"\n")
|
||||
file.write(f"show-max-players = 10\n")
|
||||
file.write(f"force-key-authentication = true\n")
|
||||
file.write(f"player-info-forwarding-mode = 'modern'\n")
|
||||
file.write(f"prevent-client-proxy-connections = false\n")
|
||||
file.write(f"announce-forge = false\n")
|
||||
file.write(f"kick-existing-players = false\n")
|
||||
file.write(f"enable-player-address-logging = true\n")
|
||||
file.write(f"ping-passthrough = 'DISABLED'\n")
|
||||
file.write(f"online-mode = true\n")
|
||||
|
||||
# Write servers
|
||||
file.write(f"servers:\n")
|
||||
file.write(f"\n\n[servers]\n\n")
|
||||
for i in range(len(parameters.backend_names)):
|
||||
file.write(f" {parameters.backend_names[i]}:\n")
|
||||
file.write(
|
||||
f" motd: '&eBackend {parameters.backend_type} {parameters.backend_names[i]} (port {parameters.backend_ports[i]})'\n")
|
||||
file.write(f" address: localhost:{parameters.backend_ports[i]}\n")
|
||||
file.write(f" restricted: false\n")
|
||||
file.write(f"{parameters.backend_names[i]} = \"127.0.0.1:{parameters.backend_ports[i]}\"\n")
|
||||
|
||||
file.write(f"\n\ntry = [\n")
|
||||
for i in range(len(parameters.backend_names)):
|
||||
file.write(f" '{parameters.backend_names[i]}',\n")
|
||||
file.write(f"]\n")
|
||||
|
||||
file.write(f"\n\n[advanced]\n\n")
|
||||
file.write(f"compression-threshold = 256\n")
|
||||
file.write(f"compression-level = -1\n")
|
||||
file.write(f"login-ratelimit = 0\n")
|
||||
file.write(f"connection-timeout = 5000\n")
|
||||
file.write(f"read-timeout = 30000\n")
|
||||
file.write(f"haproxy-protocol = false\n")
|
||||
file.write(f"tcp-fast-open = false\n")
|
||||
file.write(f"bungee-plugin-message-channel = true\n")
|
||||
file.write(f"show-ping-requests = true\n")
|
||||
file.write(f"announce-proxy-commands = true\n")
|
||||
file.write(f"failover-on-unexpected-server-disconnect = true\n")
|
||||
file.write(f"log-command-executions = true\n")
|
||||
file.write(f"log-player-connections = true\n")
|
||||
file.write(f"accepts-transfers = false\n")
|
||||
|
||||
file.write(f"\n\n[forced-hosts]\n\n")
|
||||
|
||||
file.write(f"\n\n[query]\n\n")
|
||||
file.write(f"enabled = false\n")
|
||||
file.write(f"port = {parameters.proxy_port}\n")
|
||||
file.write(f"show-plugins = false\n")
|
||||
file.write(f"map = 'Test'\n")
|
||||
|
||||
# Copy plugins
|
||||
copy_plugins(parameters.proxy_plugins, parameters.proxy_plugin_folders, f"{server_dir}/plugins")
|
||||
copy_plugins(parameters.proxy_plugins, parameters.proxy_plugin_folders, f"{server_dir}/plugins", parameters)
|
||||
|
||||
# Create startup scripts
|
||||
create_start_scripts(server_dir,
|
||||
@@ -252,7 +286,7 @@ def create_start_scripts(server_directory, start_arguments):
|
||||
|
||||
|
||||
# Copies plugins and plugin folders from the source to the target
|
||||
def copy_plugins(plugins, plugin_folders, plugins_folder):
|
||||
def copy_plugins(plugins, plugin_folders, plugins_folder, parameters):
|
||||
# Copy each file from the plugin list to the server/plugins folder
|
||||
for plugin in plugins:
|
||||
# Skip if the plugin does not exist
|
||||
@@ -265,7 +299,8 @@ def copy_plugins(plugins, plugin_folders, plugins_folder):
|
||||
if os.path.exists(parent_directory):
|
||||
hit = False
|
||||
for file in os.listdir(parent_directory):
|
||||
if file.startswith(plugin_name):
|
||||
if (file.startswith(plugin_name) and file.endswith('mc.' + parameters.minecraft_version + '.jar')
|
||||
and not file.endswith('-javadoc.jar') and not file.endswith('-sources.jar')):
|
||||
shutil.copy(parent_directory + "/" + file, plugins_folder + "/" + file)
|
||||
print(f"Copied plugin {file} to {plugins_folder}")
|
||||
hit = True
|
||||
|
||||
Reference in New Issue
Block a user