Compare commits
19 Commits
c1f8a31bd3
...
74eda38558
Author | SHA1 | Date |
---|---|---|
Fisher | 74eda38558 | |
Andreas Troelsen | 29c5d7f56d | |
Andreas Troelsen | e40fc6ef84 | |
Andreas Troelsen | be6fd85a6d | |
Andreas Troelsen | b881943656 | |
Andreas Troelsen | 8e5d2f0d23 | |
Andreas Troelsen | 3b7b638b00 | |
Andreas Troelsen | eb51a31720 | |
Andreas Troelsen | 82f00c5535 | |
Andreas Troelsen | d8fdbb80c0 | |
Andreas Troelsen | e5ffe169a1 | |
Andreas Troelsen | 798ae0f578 | |
Andreas Troelsen | 84776990b9 | |
Andreas Troelsen | 590f877756 | |
Andreas Troelsen | 932b9de8f2 | |
Andreas Troelsen | 614d95683e | |
Andreas Troelsen | 4c855e6705 | |
Fisher2911 | 3d107479b5 | |
Fisher2911 | d8304ce0b6 |
|
@ -1,15 +1,20 @@
|
|||
name: build
|
||||
|
||||
on:
|
||||
on:
|
||||
workflow_dispatch:
|
||||
push:
|
||||
branches:
|
||||
- '**'
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
outputs:
|
||||
version: ${{ steps.version.outputs.version }}
|
||||
|
||||
steps:
|
||||
- name: 'Checkout source code'
|
||||
- name: 'Checkout'
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: 'Set up JDK'
|
||||
|
@ -19,11 +24,56 @@ jobs:
|
|||
distribution: 'adopt'
|
||||
cache: 'gradle'
|
||||
|
||||
- name: 'Build, test, and package'
|
||||
- name: 'Build'
|
||||
run: ./gradlew build --no-daemon
|
||||
|
||||
- name: 'Upload artifact'
|
||||
uses: actions/upload-artifact@v3
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: MobArena.jar
|
||||
path: build/libs/MobArena.jar
|
||||
path: build/libs/MobArena-*.jar
|
||||
|
||||
- name: 'Output version'
|
||||
id: version
|
||||
run: |
|
||||
version=$(
|
||||
unzip -p build/libs/MobArena-*.jar plugin.yml \
|
||||
| grep '^version: ' \
|
||||
| awk '{printf $2}' \
|
||||
| tr -d "'" \
|
||||
)
|
||||
echo "version=${version}" >> "${GITHUB_OUTPUT}"
|
||||
|
||||
draft:
|
||||
needs: build
|
||||
|
||||
if: |
|
||||
needs.build.result == 'success' &&
|
||||
github.ref_name == 'master' &&
|
||||
startsWith(github.event.head_commit.message, 'Release ') &&
|
||||
!endsWith(needs.build.outputs.version, '-SNAPSHOT')
|
||||
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
permissions:
|
||||
contents: write
|
||||
|
||||
env:
|
||||
VERSION: ${{ needs.build.outputs.version }}
|
||||
|
||||
steps:
|
||||
- name: 'Checkout'
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: 'Download artifact'
|
||||
uses: actions/download-artifact@v4
|
||||
with:
|
||||
name: MobArena.jar
|
||||
|
||||
- name: 'Extract release notes'
|
||||
run: scripts/extract-release-notes -f github "${VERSION}" > release-notes.md
|
||||
|
||||
- name: 'Create release draft'
|
||||
run: gh release create "${VERSION}" --draft --notes-file release-notes.md MobArena-*.jar
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ github.token }}
|
||||
|
|
|
@ -0,0 +1,77 @@
|
|||
name: publish-curseforge
|
||||
|
||||
on:
|
||||
release:
|
||||
types:
|
||||
- 'released'
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
tag_name:
|
||||
description: 'The tag name of the release to publish'
|
||||
required: true
|
||||
type: string
|
||||
|
||||
jobs:
|
||||
publish:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
env:
|
||||
TAG_NAME: ${{ github.event.release.tag_name || inputs.tag_name }}
|
||||
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Download release assets
|
||||
run: gh release download "${TAG_NAME}"
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ github.token }}
|
||||
|
||||
- name: Publish to CurseForge
|
||||
run: |
|
||||
echo 'Extract release notes'
|
||||
changelog=$(scripts/extract-release-notes -f curse "${TAG_NAME}")
|
||||
|
||||
echo 'Look up game version IDs'
|
||||
game_version_type_id=1
|
||||
game_version_names='"1.20","1.19","1.18","1.17","1.16","1.15","1.14","1.13"'
|
||||
|
||||
type_condition="(.gameVersionTypeID == ${game_version_type_id})"
|
||||
name_condition="(.name | startswith(${game_version_names}))"
|
||||
|
||||
game_version_ids=$(
|
||||
curl -s -X GET 'https://minecraft.curseforge.com/api/game/versions' \
|
||||
-H "X-Api-Token: ${{ secrets.CURSEFORGE_TOKEN }}" \
|
||||
| jq -c ".[] | select(${type_condition} and ${name_condition}) | .id" \
|
||||
| paste -sd, - \
|
||||
)
|
||||
|
||||
echo 'Create metadata file'
|
||||
cat << EOF > metadata.jq
|
||||
{
|
||||
changelog: \$changelog,
|
||||
changelogType: "html",
|
||||
displayName: \$displayName,
|
||||
gameVersions: \$gameVersions,
|
||||
releaseType: "beta"
|
||||
}
|
||||
EOF
|
||||
|
||||
jq -c -n \
|
||||
--arg changelog "${changelog}" \
|
||||
--arg displayName "MobArena v${TAG_NAME}" \
|
||||
--argjson gameVersions "[${game_version_ids}]" \
|
||||
-f metadata.jq \
|
||||
> metadata.json
|
||||
|
||||
echo 'Publish build to CurseForge'
|
||||
base_url='https://minecraft.curseforge.com'
|
||||
project_id=31265
|
||||
|
||||
curl -s -X POST "${base_url}/api/projects/${project_id}/upload-file" \
|
||||
-H "X-Api-Token: ${{ secrets.CURSEFORGE_TOKEN }}" \
|
||||
-F 'metadata=<metadata.json' \
|
||||
-F "file=@MobArena-${TAG_NAME}.jar"
|
|
@ -0,0 +1,79 @@
|
|||
name: publish-hangar
|
||||
|
||||
on:
|
||||
release:
|
||||
types:
|
||||
- 'released'
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
tag_name:
|
||||
description: 'The tag name of the release to publish'
|
||||
required: true
|
||||
type: string
|
||||
|
||||
jobs:
|
||||
publish:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
env:
|
||||
TAG_NAME: ${{ github.event.release.tag_name || inputs.tag_name }}
|
||||
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Download release assets
|
||||
run: gh release download "${TAG_NAME}"
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ github.token }}
|
||||
|
||||
- name: Publish to Hangar
|
||||
run: |
|
||||
echo 'Extract release notes'
|
||||
changelog=$(scripts/extract-release-notes -f hangar "${TAG_NAME}")
|
||||
|
||||
echo 'Create version upload file'
|
||||
cat << EOF > version-upload.jq
|
||||
{
|
||||
version: \$version,
|
||||
channel: "Release",
|
||||
description: \$changelog,
|
||||
platformDependencies: {
|
||||
"PAPER": [
|
||||
"1.13.x",
|
||||
"1.14.x",
|
||||
"1.15.x",
|
||||
"1.16.x",
|
||||
"1.17.x",
|
||||
"1.18.x",
|
||||
"1.19.x",
|
||||
"1.20.x"
|
||||
]
|
||||
},
|
||||
pluginDependencies: {},
|
||||
files: [
|
||||
{ platforms: ["PAPER"] }
|
||||
]
|
||||
}
|
||||
EOF
|
||||
|
||||
jq -c -n \
|
||||
--arg version "${TAG_NAME}" \
|
||||
--arg changelog "${changelog}" \
|
||||
-f version-upload.jq \
|
||||
> version-upload.json
|
||||
|
||||
echo 'Authenticate with Hangar'
|
||||
base_url='https://hangar.papermc.io/api/v1'
|
||||
key=${{ secrets.HANGAR_TOKEN }}
|
||||
jwt=$(curl -s -X POST "${base_url}/authenticate?apiKey=${key}" | jq -r '.token')
|
||||
|
||||
echo 'Publish build to Hangar'
|
||||
project_slug='MobArena'
|
||||
curl -s -X POST "${base_url}/projects/${project_slug}/upload" \
|
||||
-H "Authorization: ${jwt}" \
|
||||
-F 'versionUpload=<version-upload.json;type=application/json' \
|
||||
-F "files=@MobArena-${TAG_NAME}.jar"
|
|
@ -4,7 +4,7 @@ plugins {
|
|||
}
|
||||
|
||||
group = "com.garbagemule"
|
||||
version = "0.107.1-SNAPSHOT"
|
||||
version = "0.108"
|
||||
|
||||
repositories {
|
||||
mavenLocal()
|
||||
|
@ -58,7 +58,6 @@ tasks {
|
|||
|
||||
archiveBaseName = "MobArena"
|
||||
archiveClassifier = ""
|
||||
archiveVersion = ""
|
||||
}
|
||||
|
||||
// We're using shadowJar, so we can skip the regular jar task.
|
||||
|
|
|
@ -11,6 +11,8 @@ These changes will (most likely) be included in the next version.
|
|||
|
||||
|
||||
## [Unreleased]
|
||||
|
||||
## [0.108] - 2024-01-01
|
||||
### Added
|
||||
- Support for chest references in item syntax. The new `inv` syntax allows for referencing container indices in the config-file. This should help bridge the gap between class chests and various other parts of the config-file, such as rewards and upgrade waves.
|
||||
- Support for saved items. The new `/ma save-item` command can be used to save the currently held item to disk, which allows it to be used in various places in the config-file. This should help bridge the gap between the config-file and class chests for config-file centric setups.
|
||||
|
@ -259,7 +261,8 @@ Thanks to:
|
|||
- Swatacular for help with testing bug fixes
|
||||
- Haileykins for contributions to the code base
|
||||
|
||||
[Unreleased]: https://github.com/garbagemule/MobArena/compare/0.107...HEAD
|
||||
[Unreleased]: https://github.com/garbagemule/MobArena/compare/0.108...HEAD
|
||||
[0.108]: https://github.com/garbagemule/MobArena/compare/0.107...0.108
|
||||
[0.107]: https://github.com/garbagemule/MobArena/compare/0.106...0.107
|
||||
[0.106]: https://github.com/garbagemule/MobArena/compare/0.105...0.106
|
||||
[0.105]: https://github.com/garbagemule/MobArena/compare/0.104.2...0.105
|
||||
|
|
|
@ -0,0 +1,235 @@
|
|||
#!/usr/bin/env python3
|
||||
|
||||
import argparse
|
||||
import os
|
||||
import re
|
||||
import sys
|
||||
|
||||
|
||||
VERSION_PREFIX = '## '
|
||||
SECTION_PREFIX = '### '
|
||||
LIST_ITEM_PREFIX = '- '
|
||||
|
||||
|
||||
def main():
|
||||
args = parse_args()
|
||||
lines = extract(args.version)
|
||||
output(lines, args.format)
|
||||
|
||||
|
||||
def parse_args():
|
||||
parser = argparse.ArgumentParser()
|
||||
parser.add_argument(
|
||||
'version',
|
||||
help='the version to extract release notes from the changelog for',
|
||||
)
|
||||
parser.add_argument(
|
||||
'--format',
|
||||
'-f',
|
||||
choices=['github', 'hangar', 'spigot', 'curse'],
|
||||
help='the format to output the release notes in',
|
||||
)
|
||||
|
||||
return parser.parse_args()
|
||||
|
||||
|
||||
def extract(target):
|
||||
filename = 'changelog.md'
|
||||
if not os.path.isfile(filename):
|
||||
filename = os.path.join('..', filename)
|
||||
if not os.path.isfile(filename):
|
||||
print('error: changelog.md not found!')
|
||||
sys.exit(1)
|
||||
|
||||
lines = []
|
||||
|
||||
with open(filename) as changelog:
|
||||
found = False
|
||||
|
||||
for entry in changelog:
|
||||
if entry.startswith(VERSION_PREFIX):
|
||||
if found:
|
||||
break
|
||||
|
||||
i = entry.find('[') + 1
|
||||
j = entry.find(']')
|
||||
version = entry[i:j]
|
||||
|
||||
if version == target:
|
||||
if version[0].isdigit():
|
||||
version = f'v{version}'
|
||||
|
||||
lines.append(f'{VERSION_PREFIX}{version}')
|
||||
lines.append('')
|
||||
found = True
|
||||
|
||||
continue
|
||||
|
||||
if not found:
|
||||
continue
|
||||
|
||||
lines.append(entry.strip())
|
||||
|
||||
if not found:
|
||||
print(f'error: version {target} not found!')
|
||||
sys.exit(1)
|
||||
|
||||
return lines
|
||||
|
||||
|
||||
def output(lines, fmt):
|
||||
if fmt == 'github':
|
||||
output_as_github_markdown(lines)
|
||||
elif fmt == 'hangar':
|
||||
output_as_hangar_markdown(lines)
|
||||
elif fmt == 'spigot':
|
||||
output_as_spigot_bbcode(lines)
|
||||
elif fmt == 'curse':
|
||||
output_as_curseforge_html(lines)
|
||||
else:
|
||||
output_raw(lines)
|
||||
|
||||
|
||||
def output_as_github_markdown(lines):
|
||||
"""
|
||||
GitHub Releases Markdown is printed as the raw output from the changelog
|
||||
except for the version header (the first line), because the version number
|
||||
is already used as the release title, so we don't want it to appear twice.
|
||||
"""
|
||||
output_raw(lines[1:])
|
||||
|
||||
|
||||
def output_as_hangar_markdown(lines):
|
||||
"""
|
||||
Hangar Versions use Markdown in the same format as GitHub Releases, so we
|
||||
don't actually need to do anything else here either. Just strip the first
|
||||
line so we don't get a duplicate header.
|
||||
"""
|
||||
output_raw(lines[1:])
|
||||
|
||||
|
||||
def output_as_spigot_bbcode(lines):
|
||||
"""
|
||||
Spigot uses BBCode for resource update descriptions. It's very similar to
|
||||
regular HTML, which makes it fairly easy to convert from Markdown. We just
|
||||
need to use a [FONT] tag with Courier New for code bits.
|
||||
"""
|
||||
listing = False
|
||||
|
||||
for line in lines:
|
||||
line = line.strip()
|
||||
|
||||
if line.startswith(VERSION_PREFIX):
|
||||
i = len(VERSION_PREFIX)
|
||||
version = line[i:]
|
||||
print(f'[B]{version}[/B]')
|
||||
continue
|
||||
|
||||
if line.startswith(SECTION_PREFIX):
|
||||
if listing:
|
||||
print('[/LIST]')
|
||||
listing = False
|
||||
|
||||
i = len(SECTION_PREFIX)
|
||||
section = line[i:]
|
||||
print(f'[B]{section}:[/B]')
|
||||
continue
|
||||
|
||||
if line.startswith(LIST_ITEM_PREFIX):
|
||||
if not listing:
|
||||
print('[LIST]')
|
||||
listing = True
|
||||
|
||||
i = len(LIST_ITEM_PREFIX)
|
||||
item = line[i:]
|
||||
|
||||
# Replace **bold** text
|
||||
item = re.sub(r'\*\*(.*?)\*\*', r'[B]\1[/B]', item)
|
||||
|
||||
# Replace _italic_ text
|
||||
item = re.sub(r'_(.*?)_', r'[I]\1[/I]', item)
|
||||
|
||||
# Replace `code` text
|
||||
item = re.sub(r'`(.*?)`', r'[FONT=Courier New]\1[/FONT]', item)
|
||||
|
||||
# Replace [links](url)
|
||||
item = re.sub(r'\[([^\]]+)]\(([^)]+)\)', r'[URL=\2]\1[/URL]', item)
|
||||
|
||||
print(f'[*]{item}')
|
||||
continue
|
||||
|
||||
if len(line) > 0:
|
||||
print(line)
|
||||
|
||||
if listing:
|
||||
print('[/LIST]')
|
||||
|
||||
|
||||
def output_as_curseforge_html(lines):
|
||||
"""
|
||||
CurseForge uses regular HTML for file update descriptions, which makes it
|
||||
fairly easy to convert from Markdown. Angled brackets need to be replaced
|
||||
with their HTML entity equivalents, but other than that it's very similar
|
||||
to the Spigot BBCode conversion.
|
||||
"""
|
||||
listing = False
|
||||
|
||||
for line in lines:
|
||||
line = line.strip()
|
||||
|
||||
if line.startswith(VERSION_PREFIX):
|
||||
i = len(VERSION_PREFIX)
|
||||
version = line[i:]
|
||||
print(f'<p><strong>{version}</strong></p>')
|
||||
continue
|
||||
|
||||
if line.startswith(SECTION_PREFIX):
|
||||
if listing:
|
||||
print('</ul>')
|
||||
listing = False
|
||||
|
||||
i = len(SECTION_PREFIX)
|
||||
section = line[i:]
|
||||
print(f'<p><strong>{section}:</strong></p>')
|
||||
continue
|
||||
|
||||
if line.startswith(LIST_ITEM_PREFIX):
|
||||
if not listing:
|
||||
print('<ul>')
|
||||
listing = True
|
||||
|
||||
i = len(LIST_ITEM_PREFIX)
|
||||
item = line[i:]
|
||||
|
||||
# Replace angled brackets
|
||||
item = item.replace('<', '<')
|
||||
item = item.replace('>', '>')
|
||||
|
||||
# Replace **bold** text
|
||||
item = re.sub(r'\*\*(.*?)\*\*', r'<strong>\1</strong>', item)
|
||||
|
||||
# Replace _italic_ text
|
||||
item = re.sub(r'_(.*?)_', r'<emph>\1</emph>', item)
|
||||
|
||||
# Replace `code` text
|
||||
item = re.sub(r'`(.*?)`', r'<code>\1</code>', item)
|
||||
|
||||
# Replace [links](url)
|
||||
item = re.sub(r'\[([^\]]+)]\(([^)]+)\)', r'<a href="\2">\1</a>', item)
|
||||
|
||||
print(f'<li>{item}</li>')
|
||||
continue
|
||||
|
||||
if len(line) > 0:
|
||||
print(line)
|
||||
|
||||
if listing:
|
||||
print('</ul>')
|
||||
|
||||
|
||||
def output_raw(lines):
|
||||
[print(line.strip()) for line in lines]
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
|
@ -268,6 +268,9 @@ public class ArenaClass
|
|||
if (arena != null) {
|
||||
try {
|
||||
arena.getInventoryManager().equip(p);
|
||||
if (arena.isKeepDrops()) {
|
||||
arena.getInventoryManager().setOriginalItemsPDC(arena.getPlugin(), p);
|
||||
}
|
||||
removeBannedItems(p.getInventory());
|
||||
} catch (Exception e) {
|
||||
am.getPlugin().getLogger().severe("Failed to give " + p.getName() + " their own items: " + e.getMessage());
|
||||
|
|
|
@ -1,15 +1,9 @@
|
|||
package com.garbagemule.MobArena;
|
||||
|
||||
import static com.garbagemule.MobArena.util.config.ConfigUtils.makeSection;
|
||||
|
||||
import com.garbagemule.MobArena.ScoreboardManager.NullScoreboardManager;
|
||||
import com.garbagemule.MobArena.announce.Announcer;
|
||||
import com.garbagemule.MobArena.announce.MessengerAnnouncer;
|
||||
import com.garbagemule.MobArena.announce.TitleAnnouncer;
|
||||
import com.garbagemule.MobArena.steps.Step;
|
||||
import com.garbagemule.MobArena.steps.StepFactory;
|
||||
import com.garbagemule.MobArena.steps.PlayerJoinArena;
|
||||
import com.garbagemule.MobArena.steps.PlayerSpecArena;
|
||||
import com.garbagemule.MobArena.events.ArenaEndEvent;
|
||||
import com.garbagemule.MobArena.events.ArenaPlayerDeathEvent;
|
||||
import com.garbagemule.MobArena.events.ArenaPlayerJoinEvent;
|
||||
|
@ -22,6 +16,12 @@ import com.garbagemule.MobArena.region.ArenaRegion;
|
|||
import com.garbagemule.MobArena.repairable.Repairable;
|
||||
import com.garbagemule.MobArena.repairable.RepairableComparator;
|
||||
import com.garbagemule.MobArena.repairable.RepairableContainer;
|
||||
import com.garbagemule.MobArena.steps.CompositeStep;
|
||||
import com.garbagemule.MobArena.steps.KeepDropsStep;
|
||||
import com.garbagemule.MobArena.steps.PlayerJoinArena;
|
||||
import com.garbagemule.MobArena.steps.PlayerSpecArena;
|
||||
import com.garbagemule.MobArena.steps.Step;
|
||||
import com.garbagemule.MobArena.steps.StepFactory;
|
||||
import com.garbagemule.MobArena.things.InvalidThingInputString;
|
||||
import com.garbagemule.MobArena.things.Thing;
|
||||
import com.garbagemule.MobArena.things.ThingPicker;
|
||||
|
@ -73,8 +73,9 @@ import java.util.concurrent.PriorityBlockingQueue;
|
|||
import java.util.logging.Level;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
public class ArenaImpl implements Arena
|
||||
{
|
||||
import static com.garbagemule.MobArena.util.config.ConfigUtils.makeSection;
|
||||
|
||||
public class ArenaImpl implements Arena {
|
||||
// General stuff
|
||||
private MobArena plugin;
|
||||
private String name;
|
||||
|
@ -98,10 +99,10 @@ public class ArenaImpl implements Arena
|
|||
private Leaderboard leaderboard;
|
||||
|
||||
// Player stuff
|
||||
private InventoryManager inventoryManager;
|
||||
private RewardManager rewardManager;
|
||||
private InventoryManager inventoryManager;
|
||||
private RewardManager rewardManager;
|
||||
private ClassLimitManager limitManager;
|
||||
private Map<Player,ArenaPlayer> arenaPlayerMap;
|
||||
private Map<Player, ArenaPlayer> arenaPlayerMap;
|
||||
|
||||
private Set<Player> arenaPlayers, lobbyPlayers, readyPlayers, specPlayers, deadPlayers;
|
||||
private Set<Player> movingPlayers;
|
||||
|
@ -110,20 +111,20 @@ public class ArenaImpl implements Arena
|
|||
|
||||
// Classes stuff
|
||||
private ArenaClass defaultClass;
|
||||
private Map<String,ArenaClass> classes;
|
||||
private Map<String, ArenaClass> classes;
|
||||
|
||||
// Blocks and pets
|
||||
private PriorityBlockingQueue<Repairable> repairQueue;
|
||||
private Set<Block> blocks;
|
||||
private Set<Block> blocks;
|
||||
private LinkedList<Repairable> repairables, containables;
|
||||
|
||||
// Monster stuff
|
||||
private MonsterManager monsterManager;
|
||||
|
||||
// Wave stuff
|
||||
private WaveManager waveManager;
|
||||
private WaveManager waveManager;
|
||||
private MASpawnThread spawnThread;
|
||||
private SheepBouncer sheepBouncer;
|
||||
private SheepBouncer sheepBouncer;
|
||||
private Map<Integer, ThingPicker> everyWaveMap, afterWaveMap;
|
||||
|
||||
// Misc
|
||||
|
@ -132,6 +133,7 @@ public class ArenaImpl implements Arena
|
|||
private AutoStartTimer autoStartTimer;
|
||||
private StartDelayTimer startDelayTimer;
|
||||
private boolean isolatedChat;
|
||||
private boolean keepDrops;
|
||||
|
||||
// Warp offsets
|
||||
private double arenaWarpOffset;
|
||||
|
@ -156,37 +158,37 @@ public class ArenaImpl implements Arena
|
|||
if (world == null)
|
||||
throw new NullPointerException("[MobArena] ERROR! World for arena '" + name + "' does not exist!");
|
||||
|
||||
this.name = name;
|
||||
this.slug = Slugs.create(name);
|
||||
this.world = world;
|
||||
this.plugin = plugin;
|
||||
this.name = name;
|
||||
this.slug = Slugs.create(name);
|
||||
this.world = world;
|
||||
this.plugin = plugin;
|
||||
this.settings = makeSection(section, "settings");
|
||||
this.region = new ArenaRegion(section, this);
|
||||
this.region = new ArenaRegion(section, this);
|
||||
|
||||
this.enabled = settings.getBoolean("enabled", false);
|
||||
this.protect = settings.getBoolean("protect", true);
|
||||
this.running = false;
|
||||
this.edit = false;
|
||||
this.edit = false;
|
||||
|
||||
this.inventoryManager = new InventoryManager();
|
||||
this.rewardManager = new RewardManager(this);
|
||||
this.rewardManager = new RewardManager(this);
|
||||
|
||||
// Warps, points and locations
|
||||
this.leaderboard = new Leaderboard(plugin, this, region.getLeaderboard());
|
||||
|
||||
// Player stuff
|
||||
this.arenaPlayerMap = new HashMap<>();
|
||||
this.arenaPlayers = new HashSet<>();
|
||||
this.lobbyPlayers = new HashSet<>();
|
||||
this.readyPlayers = new HashSet<>();
|
||||
this.specPlayers = new HashSet<>();
|
||||
this.deadPlayers = new HashSet<>();
|
||||
this.randoms = new HashSet<>();
|
||||
this.movingPlayers = new HashSet<>();
|
||||
this.arenaPlayers = new HashSet<>();
|
||||
this.lobbyPlayers = new HashSet<>();
|
||||
this.readyPlayers = new HashSet<>();
|
||||
this.specPlayers = new HashSet<>();
|
||||
this.deadPlayers = new HashSet<>();
|
||||
this.randoms = new HashSet<>();
|
||||
this.movingPlayers = new HashSet<>();
|
||||
this.leavingPlayers = new HashSet<>();
|
||||
|
||||
// Classes, items and permissions
|
||||
this.classes = plugin.getArenaMaster().getClasses();
|
||||
this.classes = plugin.getArenaMaster().getClasses();
|
||||
this.limitManager = new ClassLimitManager(this, classes, makeSection(section, "class-limits"));
|
||||
|
||||
String defaultClassName = settings.getString("default-class", null);
|
||||
|
@ -196,23 +198,23 @@ public class ArenaImpl implements Arena
|
|||
}
|
||||
|
||||
// Blocks and pets
|
||||
this.repairQueue = new PriorityBlockingQueue<>(100, new RepairableComparator());
|
||||
this.blocks = new HashSet<>();
|
||||
this.repairables = new LinkedList<>();
|
||||
this.repairQueue = new PriorityBlockingQueue<>(100, new RepairableComparator());
|
||||
this.blocks = new HashSet<>();
|
||||
this.repairables = new LinkedList<>();
|
||||
this.containables = new LinkedList<>();
|
||||
|
||||
// Monster stuff
|
||||
this.monsterManager = new MonsterManager();
|
||||
|
||||
// Wave stuff
|
||||
this.waveManager = new WaveManager(this, section.getConfigurationSection("waves"));
|
||||
this.waveManager = new WaveManager(this, section.getConfigurationSection("waves"));
|
||||
this.everyWaveMap = MAUtils.getArenaRewardMap(plugin, section, name, "every");
|
||||
this.afterWaveMap = MAUtils.getArenaRewardMap(plugin, section, name, "after");
|
||||
|
||||
// Misc
|
||||
this.eventListener = new ArenaListener(this, plugin);
|
||||
this.allowMonsters = world.getAllowMonsters();
|
||||
this.allowAnimals = world.getAllowAnimals();
|
||||
this.allowAnimals = world.getAllowAnimals();
|
||||
|
||||
this.entryFee = new ArrayList<>();
|
||||
String feeString = settings.getString("entry-fee", "");
|
||||
|
@ -227,10 +229,12 @@ public class ArenaImpl implements Arena
|
|||
}
|
||||
}
|
||||
|
||||
this.autoStartTimer = new AutoStartTimer(this);
|
||||
this.autoStartTimer = new AutoStartTimer(this);
|
||||
this.startDelayTimer = new StartDelayTimer(this, autoStartTimer);
|
||||
|
||||
this.isolatedChat = settings.getBoolean("isolated-chat", false);
|
||||
this.isolatedChat = settings.getBoolean("isolated-chat", false);
|
||||
|
||||
this.keepDrops = settings.getBoolean("keep-drops", false);
|
||||
|
||||
this.arenaWarpOffset = settings.getDouble("arena-warp-offset", 0.0);
|
||||
|
||||
|
@ -451,14 +455,10 @@ public class ArenaImpl implements Arena
|
|||
return scoreboard;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@Override
|
||||
public boolean isKeepDrops() {
|
||||
return keepDrops;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Messenger getMessenger() {
|
||||
|
@ -652,8 +652,7 @@ public class ArenaImpl implements Arena
|
|||
}
|
||||
|
||||
@Override
|
||||
public void forceStart()
|
||||
{
|
||||
public void forceStart() {
|
||||
if (running)
|
||||
return;
|
||||
|
||||
|
@ -696,8 +695,7 @@ public class ArenaImpl implements Arena
|
|||
}
|
||||
|
||||
@Override
|
||||
public boolean playerJoin(Player p, Location loc)
|
||||
{
|
||||
public boolean playerJoin(Player p, Location loc) {
|
||||
// Fire the event and check if it's been cancelled.
|
||||
ArenaPlayerJoinEvent event = new ArenaPlayerJoinEvent(p, this);
|
||||
plugin.getServer().getPluginManager().callEvent(event);
|
||||
|
@ -774,8 +772,7 @@ public class ArenaImpl implements Arena
|
|||
}
|
||||
|
||||
@Override
|
||||
public void playerReady(Player p)
|
||||
{
|
||||
public void playerReady(Player p) {
|
||||
ArenaPlayerReadyEvent event = new ArenaPlayerReadyEvent(p, this);
|
||||
plugin.getServer().getPluginManager().callEvent(event);
|
||||
if (event.isCancelled()) {
|
||||
|
@ -785,8 +782,7 @@ public class ArenaImpl implements Arena
|
|||
readyPlayers.add(p);
|
||||
|
||||
int minPlayers = getMinPlayers();
|
||||
if (minPlayers > 0 && lobbyPlayers.size() < minPlayers)
|
||||
{
|
||||
if (minPlayers > 0 && lobbyPlayers.size() < minPlayers) {
|
||||
messenger.tell(p, Msg.LOBBY_NOT_ENOUGH_PLAYERS, "" + minPlayers);
|
||||
return;
|
||||
}
|
||||
|
@ -795,8 +791,7 @@ public class ArenaImpl implements Arena
|
|||
}
|
||||
|
||||
@Override
|
||||
public boolean playerLeave(Player p)
|
||||
{
|
||||
public boolean playerLeave(Player p) {
|
||||
// Fire the event and check if it's been cancelled.
|
||||
ArenaPlayerLeaveEvent event = new ArenaPlayerLeaveEvent(p, this);
|
||||
plugin.getServer().getPluginManager().callEvent(event);
|
||||
|
@ -859,8 +854,7 @@ public class ArenaImpl implements Arena
|
|||
}
|
||||
|
||||
@Override
|
||||
public void playerDeath(Player p)
|
||||
{
|
||||
public void playerDeath(Player p) {
|
||||
// Check if we're the last player standing
|
||||
boolean last = arenaPlayers.size() == 1;
|
||||
if (last) lastStanding = p;
|
||||
|
@ -875,6 +869,19 @@ public class ArenaImpl implements Arena
|
|||
// Clear the player's inventory, and unmount
|
||||
if (arenaPlayers.remove(p)) {
|
||||
unmount(p);
|
||||
if (this.keepDrops) {
|
||||
this.inventoryManager.removeOriginalItems(plugin, p);
|
||||
final Step step = histories.get(p);
|
||||
if (step != null) {
|
||||
final Step keepDropsStep = KeepDropsStep.create(this).create(p);
|
||||
keepDropsStep.run();
|
||||
final Step composite = CompositeStep.create(
|
||||
step,
|
||||
keepDropsStep
|
||||
).create(p);
|
||||
histories.put(p, composite);
|
||||
}
|
||||
}
|
||||
clearInv(p);
|
||||
}
|
||||
|
||||
|
@ -926,7 +933,7 @@ public class ArenaImpl implements Arena
|
|||
}
|
||||
|
||||
plugin.getServer().getScheduler()
|
||||
.scheduleSyncDelayedTask(plugin, () -> playerLeave(p));
|
||||
.scheduleSyncDelayedTask(plugin, () -> playerLeave(p));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -961,13 +968,16 @@ public class ArenaImpl implements Arena
|
|||
}
|
||||
|
||||
private void rollback(Player p) {
|
||||
|
||||
Step step = histories.remove(p);
|
||||
if (step == null) {
|
||||
return;
|
||||
}
|
||||
try {
|
||||
this.inventoryManager.removeOriginalItems(this.plugin, p);
|
||||
step.undo();
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
plugin.getLogger().log(Level.SEVERE, () -> "Failed to revert player " + p.getName());
|
||||
}
|
||||
}
|
||||
|
@ -1028,20 +1038,29 @@ public class ArenaImpl implements Arena
|
|||
|
||||
private EntityType horseTypeFromAmount(int amount) {
|
||||
switch (amount % 8) {
|
||||
case 2: return EntityType.DONKEY;
|
||||
case 3: return EntityType.MULE;
|
||||
case 4: return EntityType.SKELETON_HORSE;
|
||||
case 5: return EntityType.ZOMBIE_HORSE;
|
||||
default: return EntityType.HORSE;
|
||||
case 2:
|
||||
return EntityType.DONKEY;
|
||||
case 3:
|
||||
return EntityType.MULE;
|
||||
case 4:
|
||||
return EntityType.SKELETON_HORSE;
|
||||
case 5:
|
||||
return EntityType.ZOMBIE_HORSE;
|
||||
default:
|
||||
return EntityType.HORSE;
|
||||
}
|
||||
}
|
||||
|
||||
private Material bardingFromAmount(int amount) {
|
||||
switch ((amount >> 3) % 4) {
|
||||
case 1: return Material.IRON_HORSE_ARMOR;
|
||||
case 2: return Material.GOLDEN_HORSE_ARMOR;
|
||||
case 3: return Material.DIAMOND_HORSE_ARMOR;
|
||||
default: return null;
|
||||
case 1:
|
||||
return Material.IRON_HORSE_ARMOR;
|
||||
case 2:
|
||||
return Material.GOLDEN_HORSE_ARMOR;
|
||||
case 3:
|
||||
return Material.DIAMOND_HORSE_ARMOR;
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1101,8 +1120,7 @@ public class ArenaImpl implements Arena
|
|||
}
|
||||
|
||||
@Override
|
||||
public void storeContainerContents()
|
||||
{
|
||||
public void storeContainerContents() {
|
||||
for (Location loc : region.getContainers()) {
|
||||
BlockState state = world.getBlockAt(loc).getState();
|
||||
if (state instanceof InventoryHolder) {
|
||||
|
@ -1112,23 +1130,20 @@ public class ArenaImpl implements Arena
|
|||
}
|
||||
|
||||
@Override
|
||||
public void restoreContainerContents()
|
||||
{
|
||||
public void restoreContainerContents() {
|
||||
for (Repairable r : containables) {
|
||||
r.repair();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void discardPlayer(Player p)
|
||||
{
|
||||
public void discardPlayer(Player p) {
|
||||
rollback(p);
|
||||
plugin.getArenaMaster().removePlayer(p);
|
||||
clearPlayer(p);
|
||||
}
|
||||
|
||||
private void clearPlayer(Player p)
|
||||
{
|
||||
private void clearPlayer(Player p) {
|
||||
// Remove from boss health bar
|
||||
monsterManager.getBossMonsters().forEach(entity -> {
|
||||
MABoss boss = monsterManager.getBoss(entity);
|
||||
|
@ -1148,15 +1163,13 @@ public class ArenaImpl implements Arena
|
|||
}
|
||||
|
||||
@Override
|
||||
public void repairBlocks()
|
||||
{
|
||||
public void repairBlocks() {
|
||||
while (!repairQueue.isEmpty())
|
||||
repairQueue.poll().repair();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void queueRepairable(Repairable r)
|
||||
{
|
||||
public void queueRepairable(Repairable r) {
|
||||
repairQueue.add(r);
|
||||
}
|
||||
|
||||
|
@ -1171,7 +1184,7 @@ public class ArenaImpl implements Arena
|
|||
@Override
|
||||
public void assignClass(Player p, String className) {
|
||||
ArenaPlayer arenaPlayer = arenaPlayerMap.get(p);
|
||||
ArenaClass arenaClass = classes.get(className);
|
||||
ArenaClass arenaClass = classes.get(className);
|
||||
|
||||
if (arenaPlayer == null || arenaClass == null) {
|
||||
return;
|
||||
|
@ -1203,7 +1216,7 @@ public class ArenaImpl implements Arena
|
|||
@Override
|
||||
public void assignClassGiveInv(Player p, String className, ItemStack[] source) {
|
||||
ArenaPlayer arenaPlayer = arenaPlayerMap.get(p);
|
||||
ArenaClass arenaClass = classes.get(className);
|
||||
ArenaClass arenaClass = classes.get(className);
|
||||
|
||||
if (arenaPlayer == null || arenaClass == null) {
|
||||
return;
|
||||
|
@ -1232,7 +1245,7 @@ public class ArenaImpl implements Arena
|
|||
ItemStack offhand = null;
|
||||
|
||||
// Check the very last slot to see if it'll work as a helmet
|
||||
int last = contents.length-1;
|
||||
int last = contents.length - 1;
|
||||
if (contents[last] != null) {
|
||||
helmet = contents[last];
|
||||
if (arenaClass.hasUnbreakableArmor()) {
|
||||
|
@ -1242,7 +1255,7 @@ public class ArenaImpl implements Arena
|
|||
}
|
||||
|
||||
// Check the remaining three of the four last slots for armor
|
||||
for (int i = contents.length-1; i > contents.length-5; i--) {
|
||||
for (int i = contents.length - 1; i > contents.length - 5; i--) {
|
||||
if (contents[i] == null) continue;
|
||||
|
||||
String[] parts = contents[i].getType().name().split("_");
|
||||
|
@ -1255,10 +1268,17 @@ public class ArenaImpl implements Arena
|
|||
}
|
||||
switch (type) {
|
||||
case "ELYTRA":
|
||||
case "CHESTPLATE": chestplate = stack; break;
|
||||
case "LEGGINGS": leggings = stack; break;
|
||||
case "BOOTS": boots = stack; break;
|
||||
default: break;
|
||||
case "CHESTPLATE":
|
||||
chestplate = stack;
|
||||
break;
|
||||
case "LEGGINGS":
|
||||
leggings = stack;
|
||||
break;
|
||||
case "BOOTS":
|
||||
boots = stack;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
contents[i] = null;
|
||||
}
|
||||
|
@ -1320,11 +1340,10 @@ public class ArenaImpl implements Arena
|
|||
}
|
||||
|
||||
@Override
|
||||
public void assignRandomClass(Player p)
|
||||
{
|
||||
public void assignRandomClass(Player p) {
|
||||
List<ArenaClass> classes = this.classes.values().stream()
|
||||
.filter(c -> c.hasPermission(p))
|
||||
.collect(Collectors.toList());
|
||||
.filter(c -> c.hasPermission(p))
|
||||
.collect(Collectors.toList());
|
||||
|
||||
if (classes.isEmpty()) {
|
||||
plugin.getLogger().info("Player '" + p.getName() + "' has no class permissions!");
|
||||
|
@ -1354,16 +1373,16 @@ public class ArenaImpl implements Arena
|
|||
|
||||
private void removePermissionAttachments(Player player) {
|
||||
player.getEffectivePermissions().stream()
|
||||
.filter(info -> info.getAttachment() != null)
|
||||
.filter(info -> info.getAttachment().getPlugin().equals(plugin))
|
||||
.map(PermissionAttachmentInfo::getAttachment)
|
||||
.forEach(PermissionAttachment::remove);
|
||||
.filter(info -> info.getAttachment() != null)
|
||||
.filter(info -> info.getAttachment().getPlugin().equals(plugin))
|
||||
.map(PermissionAttachmentInfo::getAttachment)
|
||||
.forEach(PermissionAttachment::remove);
|
||||
}
|
||||
|
||||
private void removePotionEffects(Player p) {
|
||||
p.getActivePotionEffects().stream()
|
||||
.map(PotionEffect::getType)
|
||||
.forEach(p::removePotionEffect);
|
||||
.map(PotionEffect::getType)
|
||||
.forEach(p::removePotionEffect);
|
||||
}
|
||||
|
||||
private void cleanup() {
|
||||
|
@ -1423,8 +1442,7 @@ public class ArenaImpl implements Arena
|
|||
////////////////////////////////////////////////////////////////////*/
|
||||
|
||||
@Override
|
||||
public void restoreRegion()
|
||||
{
|
||||
public void restoreRegion() {
|
||||
Collections.sort(repairables, new RepairableComparator());
|
||||
|
||||
for (Repairable r : repairables)
|
||||
|
@ -1460,14 +1478,12 @@ public class ArenaImpl implements Arena
|
|||
}
|
||||
|
||||
@Override
|
||||
public String configName()
|
||||
{
|
||||
public String configName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String arenaName()
|
||||
{
|
||||
public String arenaName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
|
@ -1477,26 +1493,22 @@ public class ArenaImpl implements Arena
|
|||
}
|
||||
|
||||
@Override
|
||||
public MobArena getPlugin()
|
||||
{
|
||||
public MobArena getPlugin() {
|
||||
return plugin;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String,ArenaClass> getClasses()
|
||||
{
|
||||
public Map<String, ArenaClass> getClasses() {
|
||||
return classes;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getPlayerCount()
|
||||
{
|
||||
public int getPlayerCount() {
|
||||
return spawnThread.getPlayerCount();
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Player> getAllPlayers()
|
||||
{
|
||||
public List<Player> getAllPlayers() {
|
||||
List<Player> result = new LinkedList<>();
|
||||
result.addAll(arenaPlayers);
|
||||
result.addAll(lobbyPlayers);
|
||||
|
@ -1506,8 +1518,7 @@ public class ArenaImpl implements Arena
|
|||
}
|
||||
|
||||
@Override
|
||||
public Collection<ArenaPlayer> getArenaPlayerSet()
|
||||
{
|
||||
public Collection<ArenaPlayer> getArenaPlayerSet() {
|
||||
return arenaPlayerMap.values();
|
||||
}
|
||||
|
||||
|
@ -1529,8 +1540,7 @@ public class ArenaImpl implements Arena
|
|||
}*/
|
||||
|
||||
@Override
|
||||
public List<Player> getNonreadyPlayers()
|
||||
{
|
||||
public List<Player> getNonreadyPlayers() {
|
||||
List<Player> result = new LinkedList<>();
|
||||
result.addAll(lobbyPlayers);
|
||||
result.removeAll(readyPlayers);
|
||||
|
@ -1636,7 +1646,7 @@ public class ArenaImpl implements Arena
|
|||
if (getClass() != other.getClass()) return false;
|
||||
|
||||
// Arenas must have different names.
|
||||
if (other instanceof ArenaImpl && ((ArenaImpl)other).name.equals(name))
|
||||
if (other instanceof ArenaImpl && ((ArenaImpl) other).name.equals(name))
|
||||
return true;
|
||||
|
||||
return false;
|
||||
|
|
|
@ -1,7 +1,8 @@
|
|||
package com.garbagemule.MobArena.formula;
|
||||
|
||||
import java.util.function.BiFunction;
|
||||
|
||||
@FunctionalInterface
|
||||
public interface BinaryOperation extends BiFunction<Double, Double, Double> {
|
||||
public interface BinaryOperation {
|
||||
|
||||
double apply(double left, double right);
|
||||
|
||||
}
|
||||
|
|
|
@ -1,7 +1,8 @@
|
|||
package com.garbagemule.MobArena.formula;
|
||||
|
||||
import java.util.function.Function;
|
||||
|
||||
@FunctionalInterface
|
||||
public interface UnaryOperation extends Function<Double, Double> {
|
||||
public interface UnaryOperation {
|
||||
|
||||
double apply(double value);
|
||||
|
||||
}
|
||||
|
|
|
@ -64,6 +64,8 @@ public interface Arena
|
|||
|
||||
int getMaxPlayers();
|
||||
|
||||
boolean isKeepDrops();
|
||||
|
||||
List<Thing> getEntryFee();
|
||||
|
||||
Set<Map.Entry<Integer, ThingPicker>> getEveryWaveEntrySet();
|
||||
|
|
|
@ -0,0 +1,34 @@
|
|||
package com.garbagemule.MobArena.steps;
|
||||
|
||||
import org.bukkit.entity.Player;
|
||||
|
||||
public class CompositeStep extends PlayerStep {
|
||||
|
||||
private final Step original;
|
||||
private final Step next;
|
||||
|
||||
|
||||
private CompositeStep(Player player, Step original, Step next) {
|
||||
super(player);
|
||||
this.original = original;
|
||||
this.next = next;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
this.original.run();
|
||||
this.next.run();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void undo() {
|
||||
this.original.undo();
|
||||
this.next.undo();
|
||||
}
|
||||
|
||||
|
||||
public static StepFactory create(Step original, Step next) {
|
||||
return player -> new CompositeStep(player, original, next);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,71 @@
|
|||
package com.garbagemule.MobArena.steps;
|
||||
|
||||
import com.garbagemule.MobArena.framework.Arena;
|
||||
import org.bukkit.configuration.file.YamlConfiguration;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Files;
|
||||
import java.util.logging.Level;
|
||||
|
||||
public class KeepDropsStep extends PlayerStep {
|
||||
|
||||
private final File keepDrops;
|
||||
private final Arena arena;
|
||||
|
||||
private ItemStack[] contents;
|
||||
private File backup;
|
||||
|
||||
private KeepDropsStep(Player player, Arena arena) {
|
||||
super(player);
|
||||
this.keepDrops = new File(arena.getPlugin().getDataFolder(), "extra-drops");
|
||||
this.arena = arena;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
contents = player.getInventory().getContents();
|
||||
createBackup();
|
||||
|
||||
player.getInventory().clear();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void undo() {
|
||||
for (ItemStack itemStack : contents) {
|
||||
if (itemStack == null) continue;
|
||||
player.getInventory().addItem(itemStack);
|
||||
}
|
||||
|
||||
arena.getInventoryManager().removeKeepDrops(player);
|
||||
deleteBackup();
|
||||
}
|
||||
|
||||
private void createBackup() {
|
||||
arena.getInventoryManager().removeOriginalItems(arena.getPlugin(), player);
|
||||
YamlConfiguration yaml = new YamlConfiguration();
|
||||
yaml.set("contents", contents);
|
||||
|
||||
backup = new File(keepDrops, player.getUniqueId().toString());
|
||||
try {
|
||||
yaml.save(backup);
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException("Failed to store keep-drops for " + player.getName(), e);
|
||||
}
|
||||
arena.getInventoryManager().putKeepDrops(player, contents);
|
||||
}
|
||||
|
||||
private void deleteBackup() {
|
||||
try {
|
||||
Files.delete(backup.toPath());
|
||||
} catch (IOException e) {
|
||||
arena.getPlugin().getLogger().log(Level.WARNING, "Couldn't delete backup inventory file for " + player.getName(), e);
|
||||
}
|
||||
}
|
||||
|
||||
public static StepFactory create(Arena arena) {
|
||||
return player -> new KeepDropsStep(player, arena);
|
||||
}
|
||||
}
|
|
@ -6,7 +6,7 @@ import org.bukkit.World;
|
|||
|
||||
import java.util.function.Supplier;
|
||||
|
||||
public class InventoryThingParser implements ThingParser {
|
||||
class InventoryThingParser implements ThingParser {
|
||||
|
||||
private static final String PREFIX = "inv(";
|
||||
private static final String SUFFIX = ")";
|
||||
|
|
|
@ -10,21 +10,17 @@ public class ThingManager implements ThingParser {
|
|||
private final List<ThingParser> parsers;
|
||||
private final ItemStackThingParser items;
|
||||
|
||||
public ThingManager(MobArena plugin, ItemStackThingParser parser) {
|
||||
public ThingManager(MobArena plugin) {
|
||||
parsers = new ArrayList<>();
|
||||
parsers.add(new CommandThingParser());
|
||||
parsers.add(new MoneyThingParser(plugin));
|
||||
parsers.add(new PermissionThingParser(plugin));
|
||||
parsers.add(new PotionEffectThingParser());
|
||||
parsers.add(new InventoryThingParser(plugin.getServer()));
|
||||
items = parser;
|
||||
items = new ItemStackThingParser();
|
||||
items.register(new SavedItemParser(plugin));
|
||||
}
|
||||
|
||||
public ThingManager(MobArena plugin) {
|
||||
this(plugin, new ItemStackThingParser());
|
||||
}
|
||||
|
||||
/**
|
||||
* Register a new thing parser in the manager.
|
||||
*
|
||||
|
|
|
@ -2,12 +2,15 @@ package com.garbagemule.MobArena.util.inventory;
|
|||
|
||||
import com.garbagemule.MobArena.MobArena;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.NamespacedKey;
|
||||
import org.bukkit.configuration.file.YamlConfiguration;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.inventory.Inventory;
|
||||
import org.bukkit.inventory.InventoryView;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
import org.bukkit.inventory.PlayerInventory;
|
||||
import org.bukkit.inventory.meta.ItemMeta;
|
||||
import org.bukkit.persistence.PersistentDataType;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.HashMap;
|
||||
|
@ -16,16 +19,28 @@ import java.util.logging.Level;
|
|||
|
||||
public class InventoryManager
|
||||
{
|
||||
private static final String ORIGINAL_ITEM_KEY = "original-item";
|
||||
|
||||
private Map<Player, ItemStack[]> inventories;
|
||||
private Map<Player, ItemStack[]> keepDrops;
|
||||
|
||||
public InventoryManager() {
|
||||
this.inventories = new HashMap<>();
|
||||
this.keepDrops = new HashMap<>();
|
||||
}
|
||||
|
||||
public void put(Player p, ItemStack[] contents) {
|
||||
inventories.put(p, contents);
|
||||
}
|
||||
|
||||
public void putKeepDrops(Player p, ItemStack[] contents) {
|
||||
keepDrops.put(p, contents);
|
||||
}
|
||||
|
||||
public ItemStack[] getKeepDrops(Player p) {
|
||||
return keepDrops.get(p);
|
||||
}
|
||||
|
||||
public void equip(Player p) {
|
||||
ItemStack[] contents = inventories.get(p);
|
||||
if (contents == null) {
|
||||
|
@ -34,10 +49,44 @@ public class InventoryManager
|
|||
p.getInventory().setContents(contents);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets PDC on the player's items from when they first joined the arena
|
||||
* So that item drops in the arena can be kept when they leave
|
||||
*/
|
||||
public void setOriginalItemsPDC(MobArena plugin, Player player) {
|
||||
final NamespacedKey key = new NamespacedKey(plugin, ORIGINAL_ITEM_KEY);
|
||||
for (ItemStack itemStack : player.getInventory().getContents()) {
|
||||
if (itemStack == null) continue;
|
||||
final ItemMeta itemMeta = itemStack.getItemMeta();
|
||||
if (itemMeta == null) continue;
|
||||
itemMeta.getPersistentDataContainer().set(key, PersistentDataType.BYTE, (byte) 1);
|
||||
itemStack.setItemMeta(itemMeta);
|
||||
}
|
||||
}
|
||||
|
||||
public void removeOriginalItems(MobArena plugin, Player player) {
|
||||
final NamespacedKey key = new NamespacedKey(plugin, ORIGINAL_ITEM_KEY);
|
||||
final ItemStack[] contents = player.getInventory().getContents();
|
||||
for (int i = 0; i < contents.length; i++) {
|
||||
final ItemStack itemStack = contents[i];
|
||||
if (itemStack == null) continue;
|
||||
final ItemMeta itemMeta = itemStack.getItemMeta();
|
||||
if (itemMeta == null) continue;
|
||||
if (itemMeta.getPersistentDataContainer().has(key, PersistentDataType.BYTE)) {
|
||||
itemStack.setType(Material.AIR);
|
||||
player.getInventory().clear(i);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void remove(Player p) {
|
||||
inventories.remove(p);
|
||||
}
|
||||
|
||||
public void removeKeepDrops(Player p) {
|
||||
keepDrops.remove(p);
|
||||
}
|
||||
|
||||
/**
|
||||
* Clear a player's inventory completely.
|
||||
* @param p a player
|
||||
|
@ -83,6 +132,8 @@ public class InventoryManager
|
|||
File inventories = new File(plugin.getDataFolder(), "inventories");
|
||||
File file = new File(inventories, p.getUniqueId().toString());
|
||||
|
||||
restoreKeepDrops(plugin, p);
|
||||
|
||||
if (!file.exists()) {
|
||||
return false;
|
||||
}
|
||||
|
@ -100,4 +151,25 @@ public class InventoryManager
|
|||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private static void restoreKeepDrops(MobArena plugin, Player p) {
|
||||
try {
|
||||
File inventories = new File(plugin.getDataFolder(), "keep-drops");
|
||||
File file = new File(inventories, p.getUniqueId().toString());
|
||||
|
||||
if (!file.exists()) {
|
||||
return;
|
||||
}
|
||||
|
||||
YamlConfiguration config = new YamlConfiguration();
|
||||
config.load(file);
|
||||
|
||||
ItemStack[] contents = config.getList("extra-drops").toArray(new ItemStack[0]);
|
||||
p.getInventory().addItem(contents);
|
||||
|
||||
file.delete();
|
||||
} catch (Exception e) {
|
||||
plugin.getLogger().log(Level.SEVERE, "Failed to restore extra drops for " + p.getName(), e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,7 +3,8 @@ author: garbagemule
|
|||
main: com.garbagemule.MobArena.MobArena
|
||||
version: '${project.version}'
|
||||
api-version: 1.13
|
||||
softdepend: [Multiverse-Core,Towny,Heroes,MagicSpells,Vault]
|
||||
softdepend: [Multiverse-Core,Towny,Heroes,MagicSpells,Vault,AdvancedEnchantments]
|
||||
loadbefore: [AdvancedEnchantments]
|
||||
commands:
|
||||
ma:
|
||||
description: Base command for MobArena
|
||||
|
|
|
@ -45,6 +45,7 @@ display-waves-as-level: false
|
|||
display-timer-as-level: false
|
||||
use-scoreboards: true
|
||||
isolated-chat: false
|
||||
keep-drops: false
|
||||
announcer-type: title
|
||||
global-join-announce: false
|
||||
global-end-announce: false
|
||||
|
|
|
@ -230,8 +230,8 @@ public class FormulaManagerIT {
|
|||
@Parameters(name = "{0} = {1}")
|
||||
public static Iterable<Object[]> data() {
|
||||
return Arrays.asList(new Object[][]{
|
||||
{"1 + +1.2", 1 + +1.2},
|
||||
{"1 + -1.2", 1 + -1.2},
|
||||
{"1 + +1.2", 1 + 1.2},
|
||||
{"1 + -1.2", 1 + (-1.2)},
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -259,8 +259,8 @@ public class FormulaManagerIT {
|
|||
@Parameters(name = "{0} = {1}")
|
||||
public static Iterable<Object[]> data() {
|
||||
return Arrays.asList(new Object[][]{
|
||||
{"1+-2", 1 + -2},
|
||||
{"3-+4", 3 - +4},
|
||||
{"1+-2", 1 + (-2)},
|
||||
{"3-+4", 3 - 4},
|
||||
{"3*7.5", 3 * 7.5},
|
||||
{"10/2.5", 10 / 2.5},
|
||||
{"9%4", 9 % 4},
|
||||
|
|
|
@ -6,7 +6,7 @@ import org.hamcrest.TypeSafeMatcher;
|
|||
|
||||
import java.util.Objects;
|
||||
|
||||
public class LexemeMatcher extends TypeSafeMatcher<Lexeme> {
|
||||
class LexemeMatcher extends TypeSafeMatcher<Lexeme> {
|
||||
|
||||
private final TokenType type;
|
||||
private final String value;
|
||||
|
|
Loading…
Reference in New Issue