13 Commits

14 changed files with 265 additions and 27 deletions

View File

@@ -6,6 +6,7 @@ import org.bukkit.configuration.ConfigurationSection;
import java.net.URI; import java.net.URI;
import java.net.URISyntaxException; import java.net.URISyntaxException;
import java.net.http.HttpRequest;
import java.util.Objects; import java.util.Objects;
public class CraftAttackApi { public class CraftAttackApi {
@@ -25,4 +26,8 @@ public class CraftAttackApi {
public static void withAuthorizationSecret(URIBuilder builder) { public static void withAuthorizationSecret(URIBuilder builder) {
builder.addParameter("secret", apiSecret); builder.addParameter("secret", apiSecret);
} }
public static void withAuthorizationHeader(HttpRequest.Builder builder) {
builder.header("Authorization", apiSecret);
}
} }

View File

@@ -6,7 +6,7 @@ import java.util.UUID;
public class CraftAttackReportRepository extends ReportRepository { public class CraftAttackReportRepository extends ReportRepository {
public CraftAttackReportRepository() { public CraftAttackReportRepository() {
super(CraftAttackApi.getBaseUri(), new RequestModifier(CraftAttackApi::withAuthorizationSecret, null)); super(CraftAttackApi.getBaseUri(), new RequestModifier(null, CraftAttackApi::withAuthorizationHeader));
} }
public ReqResp<PlayerReports> queryReports(UUID player) { public ReqResp<PlayerReports> queryReports(UUID player) {

View File

@@ -21,18 +21,17 @@ class ChatMessagesListener extends ApplianceListener<ChatMessages> {
public void onPlayerChatEvent(AsyncChatEvent event) { public void onPlayerChatEvent(AsyncChatEvent event) {
event.renderer( event.renderer(
(source, sourceDisplayName, message, viewer) -> (source, sourceDisplayName, message, viewer) ->
Component.text("") Component.text()
.append(this.getAppliance().getReportablePlayerName(source)) .append(this.getAppliance().getReportablePlayerName(source))
.append(Component.text(" > ").color(TextColor.color(Color.GRAY.asRGB()))) .append(Component.text(" > ").color(TextColor.color(Color.GRAY.asRGB())))
.append(message).color(TextColor.color(Color.SILVER.asRGB())) .append(message).color(TextColor.color(Color.SILVER.asRGB()))
.build()
); );
} }
@EventHandler(priority = EventPriority.HIGH) @EventHandler(priority = EventPriority.HIGH)
public void onPlayerJoin(PlayerJoinEvent event) { public void onPlayerJoin(PlayerJoinEvent event) {
boolean wasHidden = event.joinMessage() == null; if(event.joinMessage() == null) return;
event.joinMessage(null);
if(wasHidden) return;
IteratorUtil.onlinePlayers(player -> { IteratorUtil.onlinePlayers(player -> {
if(!Settings.instance().getSetting(player, Settings.Key.ShowJoinAndLeaveMessages, Boolean.class)) return; if(!Settings.instance().getSetting(player, Settings.Key.ShowJoinAndLeaveMessages, Boolean.class)) return;
player.sendMessage( player.sendMessage(
@@ -45,9 +44,7 @@ class ChatMessagesListener extends ApplianceListener<ChatMessages> {
@EventHandler @EventHandler
public void onPlayerLeave(PlayerQuitEvent event) { public void onPlayerLeave(PlayerQuitEvent event) {
boolean wasHidden = event.quitMessage() == null; if(event.quitMessage() == null) return;
event.quitMessage(null);
if(wasHidden) return;
IteratorUtil.onlinePlayers(player -> { IteratorUtil.onlinePlayers(player -> {
if(!Settings.instance().getSetting(player, Settings.Key.ShowJoinAndLeaveMessages, Boolean.class)) return; if(!Settings.instance().getSetting(player, Settings.Key.ShowJoinAndLeaveMessages, Boolean.class)) return;
player.sendMessage( player.sendMessage(

View File

@@ -1,7 +1,6 @@
package eu.mhsl.craftattack.spawn.common.appliances.metaGameplay.report; package eu.mhsl.craftattack.spawn.common.appliances.metaGameplay.report;
import eu.mhsl.craftattack.spawn.common.api.repositories.ReportRepository; import eu.mhsl.craftattack.spawn.common.api.repositories.ReportRepository;
import eu.mhsl.craftattack.spawn.common.api.repositories.VaroReportRepository;
import eu.mhsl.craftattack.spawn.core.Main; import eu.mhsl.craftattack.spawn.core.Main;
import eu.mhsl.craftattack.spawn.core.api.client.ReqResp; import eu.mhsl.craftattack.spawn.core.api.client.ReqResp;
import eu.mhsl.craftattack.spawn.common.api.repositories.CraftAttackReportRepository; import eu.mhsl.craftattack.spawn.common.api.repositories.CraftAttackReportRepository;
@@ -64,7 +63,7 @@ public class Report extends Appliance {
} }
private void createReport(Player issuer, ReportRepository.ReportCreationInfo reportRequest) { private void createReport(Player issuer, ReportRepository.ReportCreationInfo reportRequest) {
ReqResp<ReportRepository.ReportUrl> createdReport = this.queryRepository(VaroReportRepository.class) ReqResp<ReportRepository.ReportUrl> createdReport = this.queryRepository(CraftAttackReportRepository.class) // TODO: Besser machen!!
.createReport(reportRequest); .createReport(reportRequest);
switch(createdReport.status()) { switch(createdReport.status()) {
@@ -115,7 +114,7 @@ public class Report extends Appliance {
} }
public void queryReports(Player issuer) { public void queryReports(Player issuer) {
ReqResp<ReportRepository.PlayerReports> userReports = this.queryRepository(VaroReportRepository.class) ReqResp<ReportRepository.PlayerReports> userReports = this.queryRepository(CraftAttackReportRepository.class) // TODO: Besser machen!!
.queryReports(issuer.getUniqueId()); .queryReports(issuer.getUniqueId());
if(userReports.status() != 200) { if(userReports.status() != 200) {

View File

@@ -9,16 +9,16 @@ import org.bukkit.event.player.AsyncPlayerPreLoginEvent;
class PlayerLimiterListener extends ApplianceListener<PlayerLimit> { class PlayerLimiterListener extends ApplianceListener<PlayerLimit> {
@EventHandler @EventHandler
public void onLogin(AsyncPlayerPreLoginEvent playerPreLoginEvent) { public void onLogin(AsyncPlayerPreLoginEvent playerPreLoginEvent) {
playerPreLoginEvent.kickMessage( if(Bukkit.getOnlinePlayers().size() >= this.getAppliance().getLimit()) {
new DisconnectInfo( playerPreLoginEvent.kickMessage(
"Hohe Serverauslastung", new DisconnectInfo(
"Der Server ist momentan an seiner Kapazitätsgrenze angelangt!", "Hohe Serverauslastung",
"Bitte versuche es zu einem späteren Zeitpunkt erneut.", "Der Server ist momentan an seiner Kapazitätsgrenze angelangt!",
playerPreLoginEvent.getUniqueId() "Bitte versuche es zu einem späteren Zeitpunkt erneut.",
).getComponent() playerPreLoginEvent.getUniqueId()
); ).getComponent()
);
if(Bukkit.getOnlinePlayers().size() >= this.getAppliance().getLimit())
playerPreLoginEvent.setLoginResult(AsyncPlayerPreLoginEvent.Result.KICK_FULL); playerPreLoginEvent.setLoginResult(AsyncPlayerPreLoginEvent.Result.KICK_FULL);
}
} }
} }

View File

@@ -12,7 +12,7 @@ import java.util.UUID;
public class FeedbackRepository extends HttpRepository { public class FeedbackRepository extends HttpRepository {
public FeedbackRepository() { public FeedbackRepository() {
super(CraftAttackApi.getBaseUri(), new RequestModifier(CraftAttackApi::withAuthorizationSecret, null)); super(CraftAttackApi.getBaseUri(), new RequestModifier(null, CraftAttackApi::withAuthorizationHeader));
} }
public record Request(String event, List<UUID> users) { public record Request(String event, List<UUID> users) {

View File

@@ -8,7 +8,7 @@ import java.util.UUID;
public class WhitelistRepository extends HttpRepository { public class WhitelistRepository extends HttpRepository {
public WhitelistRepository() { public WhitelistRepository() {
super(CraftAttackApi.getBaseUri(), new RequestModifier(CraftAttackApi::withAuthorizationSecret, null)); super(CraftAttackApi.getBaseUri(), new RequestModifier(null, CraftAttackApi::withAuthorizationHeader));
} }
public record UserData( public record UserData(
@@ -21,10 +21,12 @@ public class WhitelistRepository extends HttpRepository {
) { ) {
} }
private record UserQuery(UUID uuid) {}
public ReqResp<UserData> getUserData(UUID userId) { public ReqResp<UserData> getUserData(UUID userId) {
return this.get( return this.post(
"user", "player",
parameters -> parameters.addParameter("uuid", userId.toString()), new UserQuery(userId),
UserData.class UserData.class
); );
} }

View File

@@ -0,0 +1,113 @@
package eu.mhsl.craftattack.spawn.craftattack.appliances.gameplay.ironGolemAnimation;
import eu.mhsl.craftattack.spawn.core.Main;
import eu.mhsl.craftattack.spawn.core.appliance.Appliance;
import org.bukkit.*;
import org.bukkit.block.Block;
import org.bukkit.block.BlockFace;
import org.bukkit.block.data.BlockData;
import org.bukkit.block.data.Directional;
import org.bukkit.entity.IronGolem;
import org.bukkit.entity.Player;
import org.bukkit.event.Listener;
import org.bukkit.util.Vector;
import org.jetbrains.annotations.NotNull;
import java.util.Collection;
import java.util.List;
import java.util.function.BiConsumer;
import java.util.function.Consumer;
public class IronGolemAnimation extends Appliance {
record BlockChange(Block original, BlockData fakeBlock) {}
public void onGolemSpawn(IronGolem golem) {
this.modifyGolem(golem, false);
Location golemLocation = golem.getLocation();
BlockData bodyBlockData = Bukkit.createBlockData(Material.IRON_BLOCK);
BlockData headBlockData = Bukkit.createBlockData(
Material.CARVED_PUMPKIN,
blockData -> ((Directional) blockData).setFacing(golem.getFacing())
);
Vector facingVector = golem.getFacing().getDirection().rotateAroundY(Math.toRadians(90));
Block golemCenterBlock = golemLocation.getBlock().getRelative(BlockFace.UP);
List<BlockChange> buildBlocks = List.of(
new BlockChange(golemCenterBlock.getRelative(BlockFace.DOWN), bodyBlockData),
new BlockChange(golemCenterBlock, bodyBlockData),
new BlockChange(golemCenterBlock.getLocation().add(facingVector).getBlock(), bodyBlockData),
new BlockChange(golemCenterBlock.getLocation().add(facingVector.multiply(-1)).getBlock(), bodyBlockData),
new BlockChange(golemCenterBlock.getRelative(BlockFace.UP), headBlockData)
);
Collection<Player> viewers = golemLocation.getNearbyPlayers(golemLocation.getWorld().getViewDistance() * 16);
BiConsumer<Location, BlockData> changeBlockForViewers = (location, blockData) -> {
viewers.forEach(player -> player.sendBlockChange(location, blockData));
golem.getWorld().playSound(
location,
blockData.getSoundGroup().getPlaceSound(),
SoundCategory.BLOCKS,
1f,
1f
);
};
for(int i = 0; i < buildBlocks.size(); i++) {
BlockChange blockChange = buildBlocks.get(i);
Bukkit.getScheduler().runTaskLater(
Main.instance(),
() -> changeBlockForViewers.accept(blockChange.original.getLocation(), blockChange.fakeBlock),
6L * i
);
}
Consumer<List<BlockChange>> restoreBlockChanges = (blocks) -> {
buildBlocks.forEach((blockChange) -> changeBlockForViewers.accept(
blockChange.original().getLocation(),
blockChange.original.getBlockData()
));
this.modifyGolem(golem, true);
this.spawnEffect(buildBlocks);
};
Bukkit.getScheduler().runTaskLater(
Main.instance(),
() -> restoreBlockChanges.accept(buildBlocks),
6L * buildBlocks.size() + 2
);
}
private void spawnEffect(List<BlockChange> buildBlocks) {
buildBlocks.forEach((blockChange) -> {
World world = blockChange.original.getLocation().getWorld();
world.spawnParticle(
Particle.BLOCK,
blockChange.original.getLocation().add(0.5, 0.5, 0.5),
50,
blockChange.fakeBlock
);
world.playSound(
blockChange.original.getLocation(),
blockChange.fakeBlock.getSoundGroup().getBreakSound(),
SoundCategory.BLOCKS,
1f,
1f
);
});
}
public void modifyGolem(IronGolem golem, boolean setVisible) {
golem.setInvisible(!setVisible);
golem.setInvulnerable(!setVisible);
golem.setAI(setVisible);
golem.setGravity(setVisible);
golem.setCollidable(setVisible);
}
@Override
protected @NotNull List<Listener> listeners() {
return List.of(
new NaturalIronGolemSpawnEvent()
);
}
}

View File

@@ -0,0 +1,15 @@
package eu.mhsl.craftattack.spawn.craftattack.appliances.gameplay.ironGolemAnimation;
import eu.mhsl.craftattack.spawn.core.appliance.ApplianceListener;
import org.bukkit.entity.IronGolem;
import org.bukkit.event.EventHandler;
import org.bukkit.event.entity.CreatureSpawnEvent;
class NaturalIronGolemSpawnEvent extends ApplianceListener<IronGolemAnimation> {
@EventHandler
public void onGolemSpawn(CreatureSpawnEvent event) {
if(!(event.getEntity() instanceof IronGolem golem)) return;
if(event.getSpawnReason() != CreatureSpawnEvent.SpawnReason.VILLAGE_DEFENSE) return;
this.getAppliance().onGolemSpawn(golem);
}
}

View File

@@ -0,0 +1,51 @@
package eu.mhsl.craftattack.spawn.craftattack.appliances.tooling.statistics;
import eu.mhsl.craftattack.spawn.core.Main;
import eu.mhsl.craftattack.spawn.core.api.server.HttpServer;
import eu.mhsl.craftattack.spawn.core.appliance.Appliance;
import org.bukkit.Bukkit;
import org.bukkit.Material;
import org.bukkit.Statistic;
import java.util.*;
public class Statistics extends Appliance {
record StatisticsResponse(List<PlayerStatistics> playerStatistics) {
record PlayerStatistics(String playerName, String playerUuid, List<MaterialStatistic> statistics) {
}
}
record MaterialStatistic(String name, String material, int value) {
}
record StatisticsRequest(List<MaterialStatistic> categories) {
}
@Override
public void httpApi(HttpServer.ApiBuilder apiBuilder) {
apiBuilder.post(
"getStatistics",
StatisticsRequest.class,
(statistics, request) -> {
Main.instance().getLogger().info("API requested statistics");
List<StatisticsResponse.PlayerStatistics> statisticsList = Arrays.stream(Bukkit.getOfflinePlayers())
.parallel()
.map(player -> new StatisticsResponse.PlayerStatistics(
player.getName(),
player.getUniqueId().toString(),
statistics.categories().stream()
.map(category -> {
String material = (category.material() == null || category.material().isBlank()) ? null : category.material();
return new MaterialStatistic(category.name(), material, material == null
? player.getStatistic(Statistic.valueOf(category.name()))
: player.getStatistic(Statistic.valueOf(category.name()), Material.valueOf(material))
);
})
.toList()
))
.toList();
return new StatisticsResponse(statisticsList);
}
);
}
}

View File

@@ -118,7 +118,7 @@ public class Whitelist extends Appliance {
); );
if(response.status() != HttpStatus.OK) if(response.status() != HttpStatus.OK)
throw new IllegalStateException(String.format("Http Reponse %d", response.status())); throw new IllegalStateException(String.format("Unwanted response %d!", response.status()));
return response.data(); return response.data();
} }

View File

@@ -0,0 +1,16 @@
package eu.mhsl.craftattack.spawn.craftattack.appliances.tweaks.phantomReducer;
import eu.mhsl.craftattack.spawn.core.appliance.Appliance;
import org.bukkit.event.Listener;
import org.jetbrains.annotations.NotNull;
import java.util.List;
public class PhantomReducer extends Appliance {
@Override
protected @NotNull List<Listener> listeners() {
return List.of(
new PhantomSpawnListener()
);
}
}

View File

@@ -0,0 +1,16 @@
package eu.mhsl.craftattack.spawn.craftattack.appliances.tweaks.phantomReducer;
import eu.mhsl.craftattack.spawn.core.appliance.ApplianceListener;
import org.bukkit.entity.Phantom;
import org.bukkit.event.EventHandler;
import org.bukkit.event.entity.CreatureSpawnEvent;
import java.util.concurrent.ThreadLocalRandom;
class PhantomSpawnListener extends ApplianceListener<PhantomReducer> {
@EventHandler
public void onPhantomSpawn(CreatureSpawnEvent event) {
if(!(event.getEntity() instanceof Phantom)) return;
if(ThreadLocalRandom.current().nextDouble() > 0.8) event.setCancelled(true);
}
}

24
local.gradle.example Normal file
View File

@@ -0,0 +1,24 @@
tasks.register('deployVaroPlugin', Copy) {
dependsOn ":varo:shadowJar"
from { project(":varo").shadowJar.archivePath }
into file('path') // path to plugins folder
rename { fileName -> "varo.jar" }
}
tasks.register("uploadVaroPlugin") {
dependsOn(":varo:shadowJar")
doLast {
def jarFile = project(":varo").tasks.named("shadowJar").get().outputs.files.singleFile
exec {
commandLine "scp", "-4", "-P", "22", jarFile.absolutePath, "user@host:path/varo.jar"
}
}
}
tasks.register('deployCraftAttackPlugin', Copy) {
dependsOn ":craftattack:shadowJar"
from { project(":craftattack").shadowJar.archivePath }
into file('path') // path to plugins folder
rename { fileName -> "craftattack.jar" }
}