commit 6532f9c2a2c8c132f7d7b413ef572c120ee6e6ba
Author: NullBite <me@nullbite.com>
Date:   Mon Jun 12 21:41:24 2023 -0400

    Initial commit

diff --git a/instance/eula.txt b/instance/eula.txt
new file mode 100644
index 0000000..6a598a4
--- /dev/null
+++ b/instance/eula.txt
@@ -0,0 +1,4 @@
+#By changing the setting below to TRUE you are indicating your agreement to our EULA (https://account.mojang.com/documents/minecraft_eula).
+#You also agree that tacos are tasty, and the best food in the world.
+#Sat Feb 01 21:53:13 EST 2020
+eula=TRUE
diff --git a/instance/merge.sh b/instance/merge.sh
new file mode 100755
index 0000000..538b240
--- /dev/null
+++ b/instance/merge.sh
@@ -0,0 +1,6 @@
+#!/bin/bash
+shopt -s globstar
+shopt -s nullglob
+for i in merge/**/*.{yml,yaml} ; do
+	[[ -e "${i##merge/}" ]] && yq ea -i "select(fileIndex == 0) * select(fileIndex == 1)" "${i##merge/}" "${i}"
+done
diff --git a/instance/merge/paper.yml b/instance/merge/paper.yml
new file mode 100644
index 0000000..c21d403
--- /dev/null
+++ b/instance/merge/paper.yml
@@ -0,0 +1,3 @@
+settings:
+  unsupported-settings:
+    allow-piston-duplication: true
diff --git a/instance/merge/plugins/Vivecraft-Spigot-Extensions/config.yml b/instance/merge/plugins/Vivecraft-Spigot-Extensions/config.yml
new file mode 100644
index 0000000..b58836c
--- /dev/null
+++ b/instance/merge/plugins/Vivecraft-Spigot-Extensions/config.yml
@@ -0,0 +1,5 @@
+climbey:
+  enabled: true
+  blockmode: None
+crawling:
+  enabled: true
diff --git a/instance/merge/spigot.yml b/instance/merge/spigot.yml
new file mode 100644
index 0000000..4dba572
--- /dev/null
+++ b/instance/merge/spigot.yml
@@ -0,0 +1,8 @@
+settings:
+  restart-on-crash: true
+  restart-script: start.bat
+
+world-settings:
+  default:
+    merge-radius:
+      exp: -1
diff --git a/instance/server.properties b/instance/server.properties
new file mode 100755
index 0000000..885af16
--- /dev/null
+++ b/instance/server.properties
@@ -0,0 +1,47 @@
+#Minecraft server properties
+#Sat Feb 01 20:30:08 EST 2020
+broadcast-rcon-to-ops=true
+view-distance=10
+max-build-height=256
+server-ip=
+rcon.port=25575
+level-seed=
+allow-nether=true
+gamemode=survival
+enable-command-block=true
+server-port=25565
+enable-rcon=false
+enable-query=false
+op-permission-level=4
+prevent-proxy-connections=false
+generator-settings=
+resource-pack=
+player-idle-timeout=0
+level-name=world
+rcon.password=***REMOVED***
+motd=owo what's this
+query.port=25565
+force-gamemode=false
+debug=false
+hardcore=false
+white-list=false
+broadcast-console-to-ops=true
+pvp=false
+spawn-npcs=true
+spawn-animals=true
+generate-structures=true
+snooper-enabled=true
+difficulty=normal
+function-permission-level=2
+network-compression-threshold=256
+level-type=default
+max-tick-time=60000
+spawn-monsters=true
+enforce-whitelist=false
+max-players=20
+use-native-transport=true
+spawn-protection=0
+resource-pack-sha1=
+online-mode=true
+allow-flight=true
+max-world-size=29999984
diff --git a/instance/start.bat b/instance/start.bat
new file mode 100755
index 0000000..eb6fc34
--- /dev/null
+++ b/instance/start.bat
@@ -0,0 +1,4 @@
+:;cd "$(dirname "$0")"; exec ./tmux.sh
+@echo off
+cd /D "%~dp0"
+java -Xmx1024M -Xms1024M -jar server.jar nogui
diff --git a/instance/start.sh b/instance/start.sh
new file mode 100755
index 0000000..fa539ec
--- /dev/null
+++ b/instance/start.sh
@@ -0,0 +1,10 @@
+#!/bin/bash
+cd "$(dirname "$0")"
+if ! [[ -e ./vars ]] ; then
+	echo 'Please create a "vars" file using "vars.example" as a template'
+	exit 1
+fi
+source ./vars
+
+command "$JAVA" $JAVA_PARAMS -jar "$SERVER" nogui
+sleep 10
diff --git a/instance/update_paper.py b/instance/update_paper.py
new file mode 100755
index 0000000..d316e3f
--- /dev/null
+++ b/instance/update_paper.py
@@ -0,0 +1,304 @@
+#!/usr/bin/env python3
+import requests
+import typing
+
+try:
+    import colorama
+    colorama.init()
+    COLOR_RED=colorama.Fore.RED
+    COLOR_RESET=colorama.Style.RESET_ALL
+except ImportError:
+    COLOR_RED=''
+    COLOR_RESET=''
+
+
+def dbprint(arg: typing.Any) -> typing.Any:
+    print(f'{COLOR_RED}debug>{COLOR_RESET}', repr(arg))
+    return arg
+
+
+class PaperMC:
+    '''Class for accessing PaperMC API endpoint'''
+    version = 'v2'
+    endpoint = f'https://papermc.io/api/{version}'
+
+    projects_controller = f'{endpoint}/projects'
+    url=projects_controller
+
+    @staticmethod
+    def _get(url: str) -> typing.Any:
+        r=requests.get(url)
+        return r.json()
+
+    @classmethod
+    def get_projects(cls) -> typing.List:
+        return [Project(x) \
+                for x in cls._get(cls.url)["projects"]]
+
+class PaperMC_Async(PaperMC):
+    @staticmethod
+    async def _get(url: str) -> typing.Any:
+        pass
+
+class Project(PaperMC):
+    '''An object representing a project within PaperMC'''
+    def __init__(self, project: str):
+        self.project=str(project)
+        self.project_controller=f'{self.projects_controller}/{self.project}'
+
+    def __repr__(self):
+        return str(self.project)
+
+    def get_project(self):
+        return Project(self.project)
+
+    def get_version_groups(self) -> typing.List:
+        return [VersionGroup(self.project, x) \
+                for x in self._get(self.project_controller)["version_groups"]]
+
+    def get_versions(self) -> typing.List:
+        return [Version(self.project, x) \
+                for x in self._get(self.project_controller)["versions"]]
+
+
+class _VersionParent(Project):
+    def __init__(self, project: str, version: str):
+        super().__init__(project)
+        self.version=str(version)
+        # list of builds, info
+        self.version_controller=\
+                f'{self.project_controller}/versions/{self.version}'
+        # info about version family
+        self.version_family_controller=\
+                f'{self.project_controller}/version_group/{self.version}'
+        # builds in version family
+        self.version_family_builds_controller=\
+                f'{self.version_family_controller}/builds'
+
+    def __repr__(self):
+        return str(self.version)
+
+    def get_version(self):
+        return Version(self.project, self.version)
+
+    def get_version_group(self):
+        return VersionGroup(self.project, self.version)
+
+
+class VersionGroup(_VersionParent):
+    '''
+    An object representing a group of versions of a PaperMC project
+
+    For Paper, this is usually a group of all versions of a full Minecraft release, i.e., every version within 1.18
+    '''
+    def get_info(self) -> typing.Any:
+        return self._get(self.version_family_controller)
+
+    def get_versions(self) -> typing.List:
+        return [Version(self.project, x) \
+                for x in self._get(self.version_family_controller)["versions"]]
+
+    def get_builds(self) -> typing.List:
+        return [Build(self.project, x["version"], x["build"]) \
+                for x in self._get(self.version_family_builds_controller)["builds"]]
+
+
+class Version(_VersionParent):
+    '''
+    An object representing a single version of a PaperMC project
+
+    For Paper, this is a single Minecraft version; i.e., 1.18.1
+    '''
+    def get_builds(self) -> typing.List:
+        return [Build(self.project, self.version, x) \
+                for x in self._get(self.version_controller)["builds"]]
+
+
+class Build(_VersionParent):
+    '''
+    An individual build of a single version of a PaperMC project
+    '''
+    def __init__(self, project: str, version: str, build: int=None,
+            build_data: typing.Any=None):
+        super().__init__(project, version)
+        if build is not None:
+            self.build=int(build)
+        elif build_data is not None:
+            pass
+        else:
+            raise TypeError('either build or build_data should be defined.')
+        self.version_build_controller=\
+                f'{self.version_controller}/builds/{self.build}'
+
+    def __repr__(self):
+        return str(self.build)
+
+    def get_build(self):
+        return Build(self.project, self.version, self.build)
+
+    def get_info(self):
+        return self._get(self.version_build_controller)
+
+    def get_downloads(self):
+        info=self.get_info()
+        return [Download(self.project, self.version, self.build, k, v)
+                for (k, v) in info["downloads"].items()]
+
+    def get_download_by_name(self, name: str):
+        return next(x for x in self.get_downloads() if x.download_name==name)
+
+
+class Download(Build):
+    '''
+    An artifact from a build of a PaperMC project
+    '''
+    def __init__(self, project: str, version: str, build: int, download_name: str, download: dict):
+        super().__init__(project, version, build)
+        self.download=download # dictionary including filename and sha256
+        self.download_name=download_name # name for artifact
+        self.name=download["name"] # filename for artifact
+        self.sha256=download["sha256"] # sha256 of file
+        self.download_controller=\
+                f'{self.version_build_controller}/downloads/{self.name}' # Download URL
+
+    def __repr__(self):
+        return str(f'{self.download_name}: {self.download_controller}')
+
+    def __str__(self):
+        return str(self.download_controller)
+
+get_projects=PaperMC.get_projects
+
+
+if __name__ == '__main__':
+    import argparse
+    import os
+
+    def abort(message: str, status: int=1):
+        print(message)
+        exit(status)
+
+    def get_best_item(item):
+        if item != 'auto':
+            return item
+        else:
+            if project is not None:
+                if version_like is not None:
+                    if build is not None:
+                        return 'downloads'
+                    else:
+                        return 'builds'
+                else:
+                    return 'version-groups'
+            else:
+                return 'projects'
+
+
+    # Initialize Variables
+    project=None
+    version=None
+    version_group=None
+    version_like=None
+    build=None
+    download=None
+
+    def list_items(items_to_list: str):
+        match get_best_item(items_to_list):
+            case 'projects':
+                for i in PaperMC.get_projects():
+                    print(i)
+
+            case 'versions':
+                if project is not None:
+                    for i in project.get_versions():
+                        print(i)
+
+            case 'version-groups':
+                if project is not None:
+                    for i in project.get_version_groups():
+                        print(i)
+
+            case 'builds':
+                if version_like is not None:
+                    for i in version_like.get_builds():
+                        info=i.get_info()
+                        print(i, ':', info)
+
+            case 'downloads':
+                if build is not None:
+                    for i in build.get_downloads():
+                        print(repr(i))
+
+
+
+
+    p = argparse.ArgumentParser(description=
+            f"This is a script to download files from PaperMC projects.{os.linesep}Please note that automatic updating is NOT SUPPORTED. This wrapper exists mainly for convenience to avoid manually having to wget the update. Updates should still be manually reviewed to ensure they are stable, and backups should *always* be taken.")
+    p.add_argument('--project', '-p', nargs='?', default='paper', help='project to act on (default: %(default)s)')
+    p_version=p.add_mutually_exclusive_group(required=False)
+    p_version.add_argument('--version', '-v', nargs='?', help='version number or "latest"')
+    p_version.add_argument('--version-group', '-g', nargs='?', help='version group number or "latest"')
+    p.add_argument('--build', '-b', nargs='?', help='build number or "latest"; omit to list all builds')
+    p.add_argument('--download', '-d', nargs='?', help='download name (default: %(default)s)', default='application')
+    p.add_argument('--list', '-l', nargs='?', const='auto',
+            choices=['auto', 'projects', 'versions', 'version-groups', 'builds', 'downloads'],
+            help='list items; no value or \'%(const)s\' lists the most fitting items for the supplied information')
+
+    args=p.parse_args()
+    dbprint(args)
+
+    project=Project(args.project)
+
+    # Set version object
+    if args.version is not None:
+        if str(args.version).lower() == 'latest':
+            version=project.get_versions()[-1]
+        else:
+            # version=next(x for x in project.get_versions() if str(x) == args.version)
+            version=Version(str(project), args.version)
+        version_like=version
+
+    # Set version group object
+    if args.version_group is not None:
+        if str(args.version_group).lower() == 'latest':
+            version_group=project.get_version_groups()[-1]
+        else:
+            version_group=VersionGroup(str(project), args.version_group)
+        version_like=version_group
+
+    # Set build object
+    if None not in (version_like, args.build):
+        assert version_like is not None
+        if str(args.build).lower() == 'latest':
+            build=version_like.get_builds()[-1]
+        else:
+            build=Build(str(project), str(version_like), args.build)
+
+    # Set build 
+    if None not in (version_like, build, args.download):
+        assert build is not None
+        download=build.get_download_by_name(args.download)
+
+    if args.list is not None:
+        list_items(args.list)
+
+    print(project)
+    print(version_like)
+    print(build)
+    print(download)
+
+
+    def debug():
+        print(PaperMC.endpoint)
+        print(repr(PaperMC.get_projects()))
+        p=Project('paper')
+        vg=p.get_version_groups()
+        v=p.get_versions()
+        print(vg)
+        print(v)
+        vv=VersionGroup('paper', '1.18').get_versions()[-1].get_builds()
+        print(vv)
+        latestbuild=Project('paper').get_version_groups()[-1].get_builds()[-1]
+        print(latestbuild)
+        print(latestbuild.get_download_by_name('application'))
+
diff --git a/instance/update_spigot.sh b/instance/update_spigot.sh
new file mode 100755
index 0000000..9abe2c5
--- /dev/null
+++ b/instance/update_spigot.sh
@@ -0,0 +1,8 @@
+#!/bin/bash
+version="${1:-1.16.5}"
+wget -O BuildTools.jar https://hub.spigotmc.org/jenkins/job/BuildTools/lastSuccessfulBuild/artifact/target/BuildTools.jar
+rm -r spigot-build
+java -jar BuildTools.jar --rev "${version}" -o spigot-build && \
+	mv spigot-build/* spigot.jar && \
+	rm -r spigot-build && \
+	cp spigot.jar server.jar
diff --git a/instance/vars.example b/instance/vars.example
new file mode 100644
index 0000000..de1731c
--- /dev/null
+++ b/instance/vars.example
@@ -0,0 +1,4 @@
+TMUX_SESSION=mcserver
+JAVA_PARAMS="-Dlog4j2.formatMsgNoLookups=true -Xmx1024M -Xms1024M"
+JAVA=java
+SERVER=server.jar
diff --git a/mcserver.service b/mcserver.service
new file mode 100644
index 0000000..70b3d15
--- /dev/null
+++ b/mcserver.service
@@ -0,0 +1,2 @@
+[Unit]
+
diff --git a/register.py b/register.py
new file mode 100755
index 0000000..39cfcf9
--- /dev/null
+++ b/register.py
@@ -0,0 +1,6 @@
+#!/usr/bin/env python3
+import os, sys
+
+if __name__ == '__main__':
+    import argparse
+    p = argparse.ArgumentParser
diff --git a/tmux.sh b/tmux.sh
new file mode 100755
index 0000000..190b220
--- /dev/null
+++ b/tmux.sh
@@ -0,0 +1,21 @@
+#!/bin/bash
+server="$1"
+shift
+
+if ! [[ -e ./vars ]] ; then
+	echo 'Please create a "vars" file using "vars.example" as a template'
+	exit 1
+fi
+source ./vars
+
+cmd="$1"
+shift
+
+code_clear=''
+code_send='
'
+
+case "$cmd" in
+	stop) tmux send-keys -t "$TMUX_SESSION" -l "$code_clear" 'stop' "$code_send" ;;
+	command) tmux send-keys -t "$TMUX_SESSION" -l "$code_clear" "$*" "$code_send" ;;
+	*) tmux new-window -t $TMUX_SESSION: "./start.sh" || tmux new-session -s $TMUX_SESSION "./start.sh";;
+esac