mirror of
https://github.com/Melledy/Grasscutter.git
synced 2024-11-25 00:54:31 +00:00
Merge branch 'api' into development
This commit is contained in:
commit
627a2f1ee8
3
.gitignore
vendored
3
.gitignore
vendored
@ -30,6 +30,9 @@ hs_err_pid*
|
||||
build/
|
||||
out/
|
||||
|
||||
# Ignore Gradle properties
|
||||
gradle.properties
|
||||
|
||||
# Eclipse
|
||||
.project
|
||||
.classpath
|
||||
|
76
build.gradle
76
build.gradle
@ -12,11 +12,22 @@ plugins {
|
||||
|
||||
// Apply the application plugin to add support for building a CLI application
|
||||
id 'application'
|
||||
|
||||
id 'maven-publish'
|
||||
id 'signing'
|
||||
}
|
||||
|
||||
group = 'tech.xigam'
|
||||
version = '1.0.0-dev'
|
||||
|
||||
sourceCompatibility = 17
|
||||
targetCompatibility = 17
|
||||
|
||||
java {
|
||||
withJavadocJar()
|
||||
withSourcesJar()
|
||||
}
|
||||
|
||||
repositories {
|
||||
mavenCentral()
|
||||
}
|
||||
@ -65,3 +76,68 @@ jar {
|
||||
destinationDir = file(".")
|
||||
}
|
||||
|
||||
publishing {
|
||||
publications {
|
||||
mavenJava(MavenPublication) {
|
||||
artifactId = 'grasscutter'
|
||||
from components.java
|
||||
versionMapping {
|
||||
usage('java-api') {
|
||||
fromResolutionOf('runtimeClasspath')
|
||||
}
|
||||
usage('java-runtime') {
|
||||
fromResolutionResult()
|
||||
}
|
||||
}
|
||||
pom {
|
||||
name = 'Grasscutter'
|
||||
description = 'A server software reimplementation for an anime game.'
|
||||
url = 'https://github.com/Grasscutters/Grasscutter'
|
||||
licenses {
|
||||
license {
|
||||
name = 'The Apache License, Version 2.0'
|
||||
url = 'http://www.apache.org/licenses/LICENSE-2.0.txt'
|
||||
}
|
||||
}
|
||||
developers {
|
||||
developer {
|
||||
id = 'melledy'
|
||||
name = 'Melledy'
|
||||
email = 'melledy@xigam.tech' // not a real email kek
|
||||
}
|
||||
developer {
|
||||
id = 'magix'
|
||||
name = 'Magix'
|
||||
email = 'magix@xigam.tech'
|
||||
}
|
||||
}
|
||||
scm {
|
||||
connection = 'scm:git:git@github.com:Grasscutters/Grasscutter.git'
|
||||
developerConnection = 'scm:git:ssh://github.com:Grasscutters/Grasscutter.git'
|
||||
url = 'https://github.com/Grasscutters/Grasscutter'
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
repositories {
|
||||
maven {
|
||||
// change URLs to point to your repos, e.g. http://my.org/repo
|
||||
def releasesRepoUrl = 'https://s01.oss.sonatype.org/service/local/staging/deploy/maven2/'
|
||||
def snapshotsRepoUrl = 'https://s01.oss.sonatype.org/content/repositories/snapshots/'
|
||||
url = version.endsWith('SNAPSHOT') ? snapshotsRepoUrl : releasesRepoUrl
|
||||
|
||||
name = 'sonatype'
|
||||
credentials(PasswordCredentials)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
signing {
|
||||
sign publishing.publications.mavenJava
|
||||
}
|
||||
|
||||
javadoc {
|
||||
if(JavaVersion.current().isJava9Compatible()) {
|
||||
options.addBooleanOption('html5', true)
|
||||
}
|
||||
}
|
@ -36,7 +36,7 @@ public final class Grasscutter {
|
||||
private static GameServer gameServer;
|
||||
private static PluginManager pluginManager;
|
||||
|
||||
public static final Reflections reflector = new Reflections();
|
||||
public static final Reflections reflector = new Reflections("emu.grasscutter");
|
||||
|
||||
static {
|
||||
// Declare logback configuration.
|
||||
@ -70,13 +70,13 @@ public final class Grasscutter {
|
||||
// Database
|
||||
DatabaseManager.initialize();
|
||||
|
||||
// Create plugin manager instance.
|
||||
pluginManager = new PluginManager();
|
||||
|
||||
// Create server instances.
|
||||
dispatchServer = new DispatchServer();
|
||||
gameServer = new GameServer(new InetSocketAddress(getConfig().getGameServerOptions().Ip, getConfig().getGameServerOptions().Port));
|
||||
|
||||
// Create plugin manager instance.
|
||||
pluginManager = new PluginManager();
|
||||
|
||||
// Start servers.
|
||||
if(getConfig().RunMode.equalsIgnoreCase("HYBRID")) {
|
||||
dispatchServer.start();
|
||||
|
@ -3,15 +3,10 @@ package emu.grasscutter.command.commands;
|
||||
import emu.grasscutter.Grasscutter;
|
||||
import emu.grasscutter.command.Command;
|
||||
import emu.grasscutter.command.CommandHandler;
|
||||
import emu.grasscutter.data.GenshinData;
|
||||
import emu.grasscutter.data.def.ItemData;
|
||||
import emu.grasscutter.game.GenshinPlayer;
|
||||
import emu.grasscutter.game.inventory.GenshinItem;
|
||||
import emu.grasscutter.game.inventory.Inventory;
|
||||
import emu.grasscutter.game.inventory.ItemType;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
|
||||
@Command(label = "clear", usage = "clear <all|wp|art|mat>", //Merged /clearartifacts and /clearweapons to /clear <args> [uid]
|
||||
@ -33,62 +28,62 @@ public final class ClearCommand implements CommandHandler {
|
||||
try {
|
||||
target = Integer.parseInt(args.get(0));
|
||||
GenshinPlayer targetPlayer = Grasscutter.getGameServer().getPlayerByUid(target);
|
||||
if (targetPlayer == null && sender != null) {
|
||||
if (targetPlayer == null) {
|
||||
target = sender.getUid();
|
||||
} else {
|
||||
switch (cmdSwitch){
|
||||
case "wp":
|
||||
switch (cmdSwitch) {
|
||||
case "wp" -> {
|
||||
playerInventory.getItems().values().stream()
|
||||
.filter(item -> item.getItemType() == ItemType.ITEM_WEAPON)
|
||||
.filter(item -> !item.isLocked() && !item.isEquipped())
|
||||
.forEach(item -> playerInventory.removeItem(item, item.getCount()));
|
||||
.filter(item -> item.getItemType() == ItemType.ITEM_WEAPON)
|
||||
.filter(item -> !item.isLocked() && !item.isEquipped())
|
||||
.forEach(item -> playerInventory.removeItem(item, item.getCount()));
|
||||
sender.dropMessage("Cleared weapons for " + targetPlayer.getNickname() + " .");
|
||||
break;
|
||||
case "art":
|
||||
}
|
||||
case "art" -> {
|
||||
playerInventory.getItems().values().stream()
|
||||
.filter(item -> item.getItemType() == ItemType.ITEM_RELIQUARY)
|
||||
.filter(item -> item.getLevel() == 1 && item.getExp() == 0)
|
||||
.filter(item -> !item.isLocked() && !item.isEquipped())
|
||||
.forEach(item -> playerInventory.removeItem(item, item.getCount()));
|
||||
.filter(item -> item.getItemType() == ItemType.ITEM_RELIQUARY)
|
||||
.filter(item -> item.getLevel() == 1 && item.getExp() == 0)
|
||||
.filter(item -> !item.isLocked() && !item.isEquipped())
|
||||
.forEach(item -> playerInventory.removeItem(item, item.getCount()));
|
||||
sender.dropMessage("Cleared artifacts for " + targetPlayer.getNickname() + " .");
|
||||
break;
|
||||
case "mat":
|
||||
}
|
||||
case "mat" -> {
|
||||
playerInventory.getItems().values().stream()
|
||||
.filter(item -> item.getItemType() == ItemType.ITEM_MATERIAL)
|
||||
.filter(item -> item.getLevel() == 1 && item.getExp() == 0)
|
||||
.filter(item -> !item.isLocked() && !item.isEquipped())
|
||||
.forEach(item -> playerInventory.removeItem(item, item.getCount()));
|
||||
.filter(item -> item.getItemType() == ItemType.ITEM_MATERIAL)
|
||||
.filter(item -> item.getLevel() == 1 && item.getExp() == 0)
|
||||
.filter(item -> !item.isLocked() && !item.isEquipped())
|
||||
.forEach(item -> playerInventory.removeItem(item, item.getCount()));
|
||||
sender.dropMessage("Cleared artifacts for " + targetPlayer.getNickname() + " .");
|
||||
break;
|
||||
case "all":
|
||||
}
|
||||
case "all" -> {
|
||||
playerInventory.getItems().values().stream()
|
||||
.filter(item1 -> item1.getItemType() == ItemType.ITEM_RELIQUARY)
|
||||
.filter(item1 -> item1.getLevel() == 1 && item1.getExp() == 0)
|
||||
.filter(item1 -> !item1.isLocked() && !item1.isEquipped())
|
||||
.forEach(item1 -> playerInventory.removeItem(item1, item1.getCount()));
|
||||
.filter(item1 -> item1.getItemType() == ItemType.ITEM_RELIQUARY)
|
||||
.filter(item1 -> item1.getLevel() == 1 && item1.getExp() == 0)
|
||||
.filter(item1 -> !item1.isLocked() && !item1.isEquipped())
|
||||
.forEach(item1 -> playerInventory.removeItem(item1, item1.getCount()));
|
||||
playerInventory.getItems().values().stream()
|
||||
.filter(item2 -> item2.getItemType() == ItemType.ITEM_MATERIAL)
|
||||
.filter(item2 -> !item2.isLocked() && !item2.isEquipped())
|
||||
.forEach(item2 -> playerInventory.removeItem(item2, item2.getCount()));
|
||||
.filter(item2 -> item2.getItemType() == ItemType.ITEM_MATERIAL)
|
||||
.filter(item2 -> !item2.isLocked() && !item2.isEquipped())
|
||||
.forEach(item2 -> playerInventory.removeItem(item2, item2.getCount()));
|
||||
playerInventory.getItems().values().stream()
|
||||
.filter(item3 -> item3.getItemType() == ItemType.ITEM_WEAPON)
|
||||
.filter(item3 -> item3.getLevel() == 1 && item3.getExp() == 0)
|
||||
.filter(item3 -> !item3.isLocked() && !item3.isEquipped())
|
||||
.forEach(item3 -> playerInventory.removeItem(item3, item3.getCount()));
|
||||
.filter(item3 -> item3.getItemType() == ItemType.ITEM_WEAPON)
|
||||
.filter(item3 -> item3.getLevel() == 1 && item3.getExp() == 0)
|
||||
.filter(item3 -> !item3.isLocked() && !item3.isEquipped())
|
||||
.forEach(item3 -> playerInventory.removeItem(item3, item3.getCount()));
|
||||
playerInventory.getItems().values().stream()
|
||||
.filter(item4 -> item4.getItemType() == ItemType.ITEM_FURNITURE)
|
||||
.filter(item4 -> !item4.isLocked() && !item4.isEquipped())
|
||||
.forEach(item4 -> playerInventory.removeItem(item4, item4.getCount()));
|
||||
.filter(item4 -> item4.getItemType() == ItemType.ITEM_FURNITURE)
|
||||
.filter(item4 -> !item4.isLocked() && !item4.isEquipped())
|
||||
.forEach(item4 -> playerInventory.removeItem(item4, item4.getCount()));
|
||||
playerInventory.getItems().values().stream()
|
||||
.filter(item5 -> item5.getItemType() == ItemType.ITEM_DISPLAY)
|
||||
.filter(item5 -> !item5.isLocked() && !item5.isEquipped())
|
||||
.forEach(item5 -> playerInventory.removeItem(item5, item5.getCount()));
|
||||
.filter(item5 -> item5.getItemType() == ItemType.ITEM_DISPLAY)
|
||||
.filter(item5 -> !item5.isLocked() && !item5.isEquipped())
|
||||
.forEach(item5 -> playerInventory.removeItem(item5, item5.getCount()));
|
||||
playerInventory.getItems().values().stream()
|
||||
.filter(item6 -> item6.getItemType() == ItemType.ITEM_VIRTUAL)
|
||||
.filter(item6 -> !item6.isLocked() && !item6.isEquipped())
|
||||
.forEach(item6 -> playerInventory.removeItem(item6, item6.getCount()));
|
||||
.filter(item6 -> item6.getItemType() == ItemType.ITEM_VIRTUAL)
|
||||
.filter(item6 -> !item6.isLocked() && !item6.isEquipped())
|
||||
.forEach(item6 -> playerInventory.removeItem(item6, item6.getCount()));
|
||||
sender.dropMessage("Cleared everything for " + targetPlayer.getNickname() + " .");
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (NumberFormatException ignored) {
|
||||
|
@ -6,20 +6,19 @@ import emu.grasscutter.game.GenshinPlayer;
|
||||
import emu.grasscutter.game.props.FightProperty;
|
||||
import emu.grasscutter.server.packet.send.PacketAvatarFightPropUpdateNotify;
|
||||
import emu.grasscutter.server.packet.send.PacketAvatarLifeStateChangeNotify;
|
||||
import emu.grasscutter.server.packet.send.PacketEntityFightPropUpdateNotify;
|
||||
import emu.grasscutter.server.packet.send.PacketLifeStateChangeNotify;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@Command(label = "heal", usage = "heal|h",
|
||||
description = "Heal all characters in your current team.", aliases = {"h"}, permission = "player.heal")
|
||||
public class HealCommand implements CommandHandler {
|
||||
@Command(label = "heal", usage = "heal|h", aliases = {"h"},
|
||||
description = "Heal all characters in your current team.", permission = "player.heal")
|
||||
public final class HealCommand implements CommandHandler {
|
||||
@Override
|
||||
public void execute(GenshinPlayer sender, List<String> args) {
|
||||
if (sender == null) {
|
||||
CommandHandler.sendMessage(null, "Run this command in-game.");
|
||||
return;
|
||||
}
|
||||
|
||||
sender.getTeamManager().getActiveTeam().forEach(entity -> {
|
||||
boolean isAlive = entity.isAlive();
|
||||
entity.setFightProperty(
|
||||
@ -31,6 +30,6 @@ public class HealCommand implements CommandHandler {
|
||||
entity.getWorld().broadcastPacket(new PacketAvatarLifeStateChangeNotify(entity.getAvatar()));
|
||||
}
|
||||
});
|
||||
CommandHandler.sendMessage(sender, "All characters are healed.");
|
||||
CommandHandler.sendMessage(sender, "All characters have been healed.");
|
||||
}
|
||||
}
|
||||
|
@ -9,7 +9,7 @@ import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
@Command(label = "list", description = "List online players")
|
||||
public class ListCommand implements CommandHandler {
|
||||
public final class ListCommand implements CommandHandler {
|
||||
|
||||
@Override
|
||||
public void execute(GenshinPlayer sender, List<String> args) {
|
||||
@ -19,14 +19,10 @@ public class ListCommand implements CommandHandler {
|
||||
|
||||
if (playersMap.size() != 0) {
|
||||
StringBuilder playerSet = new StringBuilder();
|
||||
|
||||
for (Map.Entry<Integer, GenshinPlayer> entry : playersMap.entrySet()) {
|
||||
playerSet.append(entry.getValue().getNickname());
|
||||
playerSet.append(", ");
|
||||
}
|
||||
|
||||
playersMap.values().forEach(player ->
|
||||
playerSet.append(player.getNickname()).append(", "));
|
||||
|
||||
String players = playerSet.toString();
|
||||
|
||||
CommandHandler.sendMessage(sender, players.substring(0, players.length() - 2));
|
||||
}
|
||||
}
|
||||
|
@ -43,7 +43,7 @@ public final class SetFetterLevelCommand implements CommandHandler {
|
||||
sender.sendPacket(new PacketAvatarFetterDataNotify(avatar));
|
||||
CommandHandler.sendMessage(sender, "Fetter level set to " + fetterLevel);
|
||||
} catch (NumberFormatException ignored) {
|
||||
CommandHandler.sendMessage(null, "Invalid fetter level.");
|
||||
CommandHandler.sendMessage(sender, "Invalid fetter level.");
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -13,7 +13,7 @@ import java.util.List;
|
||||
|
||||
@Command(label = "talent", usage = "talent <talentID> <value>",
|
||||
description = "Set talent level for your current active character", permission = "player.settalent")
|
||||
public class TalentCommand implements CommandHandler {
|
||||
public final class TalentCommand implements CommandHandler {
|
||||
|
||||
@Override
|
||||
public void execute(GenshinPlayer sender, List<String> args) {
|
||||
|
@ -9,7 +9,7 @@ import java.util.List;
|
||||
|
||||
@Command(label = "teleport", usage = "teleport <x> <y> <z>", aliases = {"tp"},
|
||||
description = "Change the player's position.", permission = "player.teleport")
|
||||
public class TelePortCommand implements CommandHandler {
|
||||
public final class TeleportCommand implements CommandHandler {
|
||||
|
||||
@Override
|
||||
public void execute(GenshinPlayer sender, List<String> args) {
|
@ -286,8 +286,6 @@ public class GachaManager {
|
||||
this.watchService = FileSystems.getDefault().newWatchService();
|
||||
Path path = new File(Grasscutter.getConfig().DATA_FOLDER).toPath();
|
||||
path.register(watchService, new WatchEvent.Kind[]{StandardWatchEventKinds.ENTRY_MODIFY}, SensitivityWatchEventModifier.HIGH);
|
||||
|
||||
server.OnGameServerTick.register(this);
|
||||
} catch (Exception e) {
|
||||
Grasscutter.getLogger().error("Unable to load the Gacha Manager Watch Service. If ServerOptions.watchGacha is true it will not auto-reload");
|
||||
e.printStackTrace();
|
||||
|
5
src/main/java/emu/grasscutter/plugin/api/Item.java
Normal file
5
src/main/java/emu/grasscutter/plugin/api/Item.java
Normal file
@ -0,0 +1,5 @@
|
||||
package emu.grasscutter.plugin.api;
|
||||
|
||||
public enum Item {
|
||||
/* TODO: Use handbook to generate an Item enum. */
|
||||
}
|
113
src/main/java/emu/grasscutter/plugin/api/PlayerHook.java
Normal file
113
src/main/java/emu/grasscutter/plugin/api/PlayerHook.java
Normal file
@ -0,0 +1,113 @@
|
||||
package emu.grasscutter.plugin.api;
|
||||
|
||||
import emu.grasscutter.game.GenshinPlayer;
|
||||
import emu.grasscutter.game.avatar.GenshinAvatar;
|
||||
import emu.grasscutter.game.entity.EntityAvatar;
|
||||
import emu.grasscutter.game.props.EnterReason;
|
||||
import emu.grasscutter.game.props.FightProperty;
|
||||
import emu.grasscutter.net.packet.GenshinPacket;
|
||||
import emu.grasscutter.net.proto.EnterTypeOuterClass.EnterType;
|
||||
import emu.grasscutter.server.packet.send.PacketAvatarFightPropUpdateNotify;
|
||||
import emu.grasscutter.server.packet.send.PacketAvatarLifeStateChangeNotify;
|
||||
import emu.grasscutter.server.packet.send.PacketPlayerEnterSceneNotify;
|
||||
import emu.grasscutter.utils.Position;
|
||||
|
||||
/**
|
||||
* Hooks into the {@link GenshinPlayer} class, adding convenient ways to do certain things.
|
||||
*/
|
||||
public final class PlayerHook {
|
||||
private final GenshinPlayer player;
|
||||
|
||||
/**
|
||||
* Hooks into the player.
|
||||
* @param player The player to hook into.
|
||||
*/
|
||||
public PlayerHook(GenshinPlayer player) {
|
||||
this.player = player;
|
||||
}
|
||||
|
||||
/**
|
||||
* Kicks a player from the server.
|
||||
*/
|
||||
public void kick() {
|
||||
this.player.getSession().close();
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends a player to another scene.
|
||||
* @param sceneId The scene to send the player to.
|
||||
*/
|
||||
public void changeScenes(int sceneId) {
|
||||
this.player.getWorld().transferPlayerToScene(this.player, sceneId, this.player.getPos());
|
||||
}
|
||||
|
||||
/**
|
||||
* Broadcasts an avatar property notify to all world players.
|
||||
* @param property The property that was updated.
|
||||
*/
|
||||
public void updateFightProperty(FightProperty property) {
|
||||
this.broadcastPacketToWorld(new PacketAvatarFightPropUpdateNotify(this.getCurrentAvatar(), property));
|
||||
}
|
||||
|
||||
/**
|
||||
* Broadcasts the packet sent to all world players.
|
||||
* @param packet The packet to send.
|
||||
*/
|
||||
public void broadcastPacketToWorld(GenshinPacket packet) {
|
||||
this.player.getWorld().broadcastPacket(packet);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the currently equipped avatar's health.
|
||||
* @param health The health to set the avatar to.
|
||||
*/
|
||||
public void setHealth(float health) {
|
||||
this.getCurrentAvatarEntity().setFightProperty(FightProperty.FIGHT_PROP_CUR_HP, health);
|
||||
this.updateFightProperty(FightProperty.FIGHT_PROP_CUR_HP);
|
||||
}
|
||||
|
||||
/**
|
||||
* Revives the specified avatar.
|
||||
* @param avatar The avatar to revive.
|
||||
*/
|
||||
public void reviveAvatar(GenshinAvatar avatar) {
|
||||
this.broadcastPacketToWorld(new PacketAvatarLifeStateChangeNotify(avatar));
|
||||
}
|
||||
|
||||
/**
|
||||
* Teleports a player to a position.
|
||||
* This will **not** transfer the player to another scene.
|
||||
* @param position The position to teleport the player to.
|
||||
*/
|
||||
public void teleport(Position position) {
|
||||
this.player.getPos().set(position);
|
||||
this.player.sendPacket(new PacketPlayerEnterSceneNotify(this.player,
|
||||
EnterType.EnterJump, EnterReason.TransPoint,
|
||||
this.player.getSceneId(), position
|
||||
));
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the currently selected avatar's max health.
|
||||
* @return The max health as a float.
|
||||
*/
|
||||
public float getMaxHealth() {
|
||||
return this.getCurrentAvatarEntity().getFightProperty(FightProperty.FIGHT_PROP_MAX_HP);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the currently selected avatar in entity form.
|
||||
* @return The avatar as an {@link EntityAvatar}.
|
||||
*/
|
||||
public EntityAvatar getCurrentAvatarEntity() {
|
||||
return this.player.getTeamManager().getCurrentAvatarEntity();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the currently selected avatar.
|
||||
* @return The avatar as an {@link GenshinAvatar}.
|
||||
*/
|
||||
public GenshinAvatar getCurrentAvatar() {
|
||||
return this.getCurrentAvatarEntity().getAvatar();
|
||||
}
|
||||
}
|
2
src/main/java/emu/grasscutter/plugin/api/README.md
Normal file
2
src/main/java/emu/grasscutter/plugin/api/README.md
Normal file
@ -0,0 +1,2 @@
|
||||
# Grasscutter Plugin API
|
||||
**Warning!** As of now, this is a work in progress and isn't completely documented.
|
41
src/main/java/emu/grasscutter/plugin/api/ServerHook.java
Normal file
41
src/main/java/emu/grasscutter/plugin/api/ServerHook.java
Normal file
@ -0,0 +1,41 @@
|
||||
package emu.grasscutter.plugin.api;
|
||||
|
||||
import emu.grasscutter.game.GenshinPlayer;
|
||||
import emu.grasscutter.server.game.GameServer;
|
||||
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Hooks into the {@link GameServer} class, adding convenient ways to do certain things.
|
||||
*/
|
||||
public final class ServerHook {
|
||||
private static ServerHook instance;
|
||||
private final GameServer server;
|
||||
|
||||
/**
|
||||
* Gets the server hook instance.
|
||||
* @return A {@link ServerHook} singleton.
|
||||
*/
|
||||
public static ServerHook getInstance() {
|
||||
return instance;
|
||||
}
|
||||
|
||||
/**
|
||||
* Hooks into a server.
|
||||
* @param server The server to hook into.
|
||||
*/
|
||||
public ServerHook(GameServer server) {
|
||||
this.server = server;
|
||||
|
||||
instance = this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets all online players.
|
||||
* @return Players connected to the server.
|
||||
*/
|
||||
public List<GenshinPlayer> getOnlinePlayers() {
|
||||
return new LinkedList<>(this.server.getPlayers().values());
|
||||
}
|
||||
}
|
@ -103,8 +103,8 @@ public final class DispatchServer {
|
||||
byte[] decoded2 = Base64.getDecoder().decode(query_cur_region);
|
||||
QueryCurrRegionHttpRsp regionQuery = QueryCurrRegionHttpRsp.parseFrom(decoded2);
|
||||
|
||||
List<RegionSimpleInfo> servers = new ArrayList<RegionSimpleInfo>();
|
||||
List<String> usedNames = new ArrayList<String>(); // List to check for potential naming conflicts
|
||||
List<RegionSimpleInfo> servers = new ArrayList<>();
|
||||
List<String> usedNames = new ArrayList<>(); // List to check for potential naming conflicts
|
||||
if (Grasscutter.getConfig().RunMode.equalsIgnoreCase("HYBRID")) { // Automatically add the game server if in
|
||||
// hybrid mode
|
||||
RegionSimpleInfo server = RegionSimpleInfo.newBuilder()
|
||||
@ -268,7 +268,10 @@ public final class DispatchServer {
|
||||
Grasscutter.getLogger()
|
||||
.info(String.format("[Dispatch] Client %s request: query_region_list", t.getRemoteAddress()));
|
||||
|
||||
responseHTML(t, regionListBase64);
|
||||
// Invoke event.
|
||||
QueryAllRegionsEvent event = new QueryAllRegionsEvent(regionListBase64); event.call();
|
||||
// Respond with event result.
|
||||
responseHTML(t, event.getRegionList());
|
||||
});
|
||||
|
||||
for (String regionName : regions.keySet()) {
|
||||
|
@ -10,6 +10,10 @@ public abstract class ServerEvent extends Event {
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
public Type getServerType() {
|
||||
return this.type;
|
||||
}
|
||||
|
||||
public enum Type {
|
||||
DISPATCH,
|
||||
GAME
|
||||
|
@ -0,0 +1,9 @@
|
||||
package emu.grasscutter.server.event.game;
|
||||
|
||||
import emu.grasscutter.server.event.ServerEvent;
|
||||
|
||||
public final class ServerTickEvent extends ServerEvent {
|
||||
public ServerTickEvent() {
|
||||
super(Type.GAME);
|
||||
}
|
||||
}
|
@ -0,0 +1,19 @@
|
||||
package emu.grasscutter.server.event.internal;
|
||||
|
||||
import emu.grasscutter.server.event.ServerEvent;
|
||||
|
||||
import java.time.OffsetDateTime;
|
||||
|
||||
public final class ServerStartEvent extends ServerEvent {
|
||||
private final OffsetDateTime startTime;
|
||||
|
||||
public ServerStartEvent(Type type, OffsetDateTime startTime) {
|
||||
super(type);
|
||||
|
||||
this.startTime = startTime;
|
||||
}
|
||||
|
||||
public OffsetDateTime getStartTime() {
|
||||
return this.startTime;
|
||||
}
|
||||
}
|
@ -0,0 +1,19 @@
|
||||
package emu.grasscutter.server.event.internal;
|
||||
|
||||
import emu.grasscutter.server.event.ServerEvent;
|
||||
|
||||
import java.time.OffsetDateTime;
|
||||
|
||||
public final class ServerStopEvent extends ServerEvent {
|
||||
private final OffsetDateTime stopTime;
|
||||
|
||||
public ServerStopEvent(Type type, OffsetDateTime stopTime) {
|
||||
super(type);
|
||||
|
||||
this.stopTime = stopTime;
|
||||
}
|
||||
|
||||
public OffsetDateTime getStopTime() {
|
||||
return this.stopTime;
|
||||
}
|
||||
}
|
@ -1,6 +1,7 @@
|
||||
package emu.grasscutter.server.game;
|
||||
|
||||
import java.net.InetSocketAddress;
|
||||
import java.time.OffsetDateTime;
|
||||
import java.util.*;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
@ -20,7 +21,10 @@ import emu.grasscutter.game.shop.ShopManager;
|
||||
import emu.grasscutter.net.packet.PacketHandler;
|
||||
import emu.grasscutter.net.proto.SocialDetailOuterClass.SocialDetail;
|
||||
import emu.grasscutter.netty.MihoyoKcpServer;
|
||||
import org.greenrobot.eventbus.EventBus;
|
||||
import emu.grasscutter.server.event.ServerEvent;
|
||||
import emu.grasscutter.server.event.game.ServerTickEvent;
|
||||
import emu.grasscutter.server.event.internal.ServerStartEvent;
|
||||
import emu.grasscutter.server.event.internal.ServerStopEvent;
|
||||
|
||||
public final class GameServer extends MihoyoKcpServer {
|
||||
private final InetSocketAddress address;
|
||||
@ -36,18 +40,10 @@ public final class GameServer extends MihoyoKcpServer {
|
||||
private final MultiplayerManager multiplayerManager;
|
||||
private final DungeonManager dungeonManager;
|
||||
private final CommandMap commandMap;
|
||||
|
||||
public EventBus OnGameServerStartFinish;
|
||||
public EventBus OnGameServerTick;
|
||||
public EventBus OnGameServerStop;
|
||||
|
||||
public GameServer(InetSocketAddress address) {
|
||||
super(address);
|
||||
|
||||
OnGameServerStartFinish = EventBus.builder().throwSubscriberException(true).logNoSubscriberMessages(false).build();
|
||||
OnGameServerTick = EventBus.builder().throwSubscriberException(true).logNoSubscriberMessages(false).build();
|
||||
OnGameServerStop = EventBus.builder().throwSubscriberException(true).logNoSubscriberMessages(false).build();
|
||||
|
||||
this.setServerInitializer(new GameServerInitializer(this));
|
||||
this.address = address;
|
||||
this.packetHandler = new GameServerPacketHandler(PacketHandler.class);
|
||||
@ -178,12 +174,8 @@ public final class GameServer extends MihoyoKcpServer {
|
||||
|
||||
world.onTick();
|
||||
}
|
||||
|
||||
for (GenshinPlayer player : this.getPlayers().values()) {
|
||||
player.onTick();
|
||||
}
|
||||
|
||||
OnGameServerTick.post(new GameServerTickEvent());
|
||||
|
||||
ServerTickEvent event = new ServerTickEvent(); event.call();
|
||||
}
|
||||
|
||||
public void registerWorld(World world) {
|
||||
@ -198,12 +190,11 @@ public final class GameServer extends MihoyoKcpServer {
|
||||
@Override
|
||||
public void onStartFinish() {
|
||||
Grasscutter.getLogger().info("Game Server started on port " + address.getPort());
|
||||
|
||||
OnGameServerStartFinish.post(new GameServerStartFinishEvent());
|
||||
ServerStartEvent event = new ServerStartEvent(ServerEvent.Type.GAME, OffsetDateTime.now()); event.call();
|
||||
}
|
||||
|
||||
public void onServerShutdown() {
|
||||
OnGameServerStop.post(new GameServerStopEvent());
|
||||
ServerStopEvent event = new ServerStopEvent(ServerEvent.Type.GAME, OffsetDateTime.now()); event.call();
|
||||
|
||||
// Kick and save all players
|
||||
List<GenshinPlayer> list = new ArrayList<>(this.getPlayers().size());
|
||||
|
Loading…
Reference in New Issue
Block a user