mirror of
https://github.com/Grasscutters/Grasscutter.git
synced 2025-07-04 05:53:42 +00:00
Compare commits
19 Commits
Author | SHA1 | Date | |
---|---|---|---|
82189e03ed | |||
cef8b53dd6 | |||
43f3494073 | |||
20f0cda3e0 | |||
8692405363 | |||
9dd514a73b | |||
1940b22dc5 | |||
bb1729c227 | |||
4870871b2c | |||
2c7c8bf4fd | |||
deaa13c2af | |||
fd40575cb4 | |||
3c0e834348 | |||
27be6c31e6 | |||
87269e9ded | |||
46fee38217 | |||
6e5971df62 | |||
98375deac9 | |||
97c70f7877 |
@ -80,7 +80,7 @@ Grasscutter uses Gradle to handle dependencies & building.
|
|||||||
##### Windows
|
##### Windows
|
||||||
|
|
||||||
```shell
|
```shell
|
||||||
git clone --recurse-submodules -b unstable https://github.com/Grasscutters/Grasscutter.git
|
git clone --recurse-submodules https://github.com/Grasscutters/Grasscutter.git
|
||||||
cd Grasscutter
|
cd Grasscutter
|
||||||
.\gradlew.bat # Setting up environments
|
.\gradlew.bat # Setting up environments
|
||||||
.\gradlew jar # Compile
|
.\gradlew jar # Compile
|
||||||
@ -89,7 +89,7 @@ cd Grasscutter
|
|||||||
##### Linux (GNU)
|
##### Linux (GNU)
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
git clone --recurse-submodules -b unstable https://github.com/Grasscutters/Grasscutter.git
|
git clone --recurse-submodules https://github.com/Grasscutters/Grasscutter.git
|
||||||
cd Grasscutter
|
cd Grasscutter
|
||||||
chmod +x gradlew
|
chmod +x gradlew
|
||||||
./gradlew jar # Compile
|
./gradlew jar # Compile
|
||||||
|
@ -57,7 +57,7 @@ sourceCompatibility = JavaVersion.VERSION_17
|
|||||||
targetCompatibility = JavaVersion.VERSION_17
|
targetCompatibility = JavaVersion.VERSION_17
|
||||||
|
|
||||||
group = 'io.grasscutter'
|
group = 'io.grasscutter'
|
||||||
version = '2.0.0-unstable'
|
version = '1.6.1'
|
||||||
|
|
||||||
java {
|
java {
|
||||||
withJavadocJar()
|
withJavadocJar()
|
||||||
|
@ -1,14 +1,11 @@
|
|||||||
package emu.grasscutter;
|
package emu.grasscutter;
|
||||||
|
|
||||||
import static emu.grasscutter.config.Configuration.SERVER;
|
|
||||||
import static emu.grasscutter.utils.lang.Language.translate;
|
|
||||||
|
|
||||||
import ch.qos.logback.classic.*;
|
import ch.qos.logback.classic.*;
|
||||||
import emu.grasscutter.auth.*;
|
import emu.grasscutter.auth.*;
|
||||||
import emu.grasscutter.command.*;
|
import emu.grasscutter.command.*;
|
||||||
import emu.grasscutter.config.ConfigContainer;
|
import emu.grasscutter.config.ConfigContainer;
|
||||||
import emu.grasscutter.data.ResourceLoader;
|
import emu.grasscutter.data.ResourceLoader;
|
||||||
import emu.grasscutter.database.DatabaseManager;
|
import emu.grasscutter.database.*;
|
||||||
import emu.grasscutter.plugin.PluginManager;
|
import emu.grasscutter.plugin.PluginManager;
|
||||||
import emu.grasscutter.plugin.api.ServerHelper;
|
import emu.grasscutter.plugin.api.ServerHelper;
|
||||||
import emu.grasscutter.server.dispatch.DispatchServer;
|
import emu.grasscutter.server.dispatch.DispatchServer;
|
||||||
@ -21,16 +18,20 @@ import emu.grasscutter.tools.Tools;
|
|||||||
import emu.grasscutter.utils.*;
|
import emu.grasscutter.utils.*;
|
||||||
import emu.grasscutter.utils.lang.Language;
|
import emu.grasscutter.utils.lang.Language;
|
||||||
import io.netty.util.concurrent.FastThreadLocalThread;
|
import io.netty.util.concurrent.FastThreadLocalThread;
|
||||||
import java.io.*;
|
|
||||||
import java.util.Calendar;
|
|
||||||
import java.util.concurrent.*;
|
|
||||||
import javax.annotation.Nullable;
|
|
||||||
import lombok.*;
|
import lombok.*;
|
||||||
import org.jline.reader.*;
|
import org.jline.reader.*;
|
||||||
import org.jline.terminal.*;
|
import org.jline.terminal.*;
|
||||||
import org.reflections.Reflections;
|
import org.reflections.Reflections;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
import javax.annotation.Nullable;
|
||||||
|
import java.io.*;
|
||||||
|
import java.util.Calendar;
|
||||||
|
import java.util.concurrent.*;
|
||||||
|
|
||||||
|
import static emu.grasscutter.config.Configuration.SERVER;
|
||||||
|
import static emu.grasscutter.utils.lang.Language.translate;
|
||||||
|
|
||||||
public final class Grasscutter {
|
public final class Grasscutter {
|
||||||
public static final File configFile = new File("./config.json");
|
public static final File configFile = new File("./config.json");
|
||||||
public static final Reflections reflector = new Reflections("emu.grasscutter");
|
public static final Reflections reflector = new Reflections("emu.grasscutter");
|
||||||
@ -183,6 +184,22 @@ public final class Grasscutter {
|
|||||||
private static void onShutdown() {
|
private static void onShutdown() {
|
||||||
// Disable all plugins.
|
// Disable all plugins.
|
||||||
if (pluginManager != null) pluginManager.disablePlugins();
|
if (pluginManager != null) pluginManager.disablePlugins();
|
||||||
|
|
||||||
|
try {
|
||||||
|
// Wait for Grasscutter's thread pool to finish.
|
||||||
|
var executor = Grasscutter.getThreadPool();
|
||||||
|
executor.shutdown();
|
||||||
|
if (!executor.awaitTermination(5, TimeUnit.SECONDS)) {
|
||||||
|
executor.shutdownNow();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Wait for database operations to finish.
|
||||||
|
var dbExecutor = DatabaseHelper.getEventExecutor();
|
||||||
|
dbExecutor.shutdown();
|
||||||
|
if (!dbExecutor.awaitTermination(5, TimeUnit.SECONDS)) {
|
||||||
|
dbExecutor.shutdownNow();
|
||||||
|
}
|
||||||
|
} catch (InterruptedException ignored) { }
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -1,12 +1,13 @@
|
|||||||
package emu.grasscutter.command.commands;
|
package emu.grasscutter.command.commands;
|
||||||
|
|
||||||
import static emu.grasscutter.utils.lang.Language.translate;
|
import emu.grasscutter.command.*;
|
||||||
|
|
||||||
import emu.grasscutter.command.Command;
|
|
||||||
import emu.grasscutter.command.CommandHandler;
|
|
||||||
import emu.grasscutter.game.player.Player;
|
import emu.grasscutter.game.player.Player;
|
||||||
import emu.grasscutter.game.quest.GameQuest;
|
import emu.grasscutter.game.quest.GameQuest;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
import static emu.grasscutter.utils.lang.Language.translate;
|
||||||
|
|
||||||
@Command(
|
@Command(
|
||||||
label = "quest",
|
label = "quest",
|
||||||
@ -131,6 +132,22 @@ public final class QuestCommand implements CommandHandler {
|
|||||||
"Triggers registered for %s: %s."
|
"Triggers registered for %s: %s."
|
||||||
.formatted(questId, String.join(", ", quest.getTriggers().keySet())));
|
.formatted(questId, String.join(", ", quest.getTriggers().keySet())));
|
||||||
}
|
}
|
||||||
|
case "grouptriggers" -> {
|
||||||
|
var scene = targetPlayer.getScene();
|
||||||
|
var scriptManager = scene.getScriptManager();
|
||||||
|
|
||||||
|
var group = scriptManager.getGroupById(questId);
|
||||||
|
if (group == null) {
|
||||||
|
CommandHandler.sendMessage(sender, "The group does not exist.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
CommandHandler.sendMessage(sender,
|
||||||
|
group.triggers.entrySet().stream()
|
||||||
|
.map(entry -> "%s: %s".formatted(entry.getKey(), entry.getValue()))
|
||||||
|
.collect(Collectors.joining(", "))
|
||||||
|
);
|
||||||
|
}
|
||||||
default -> this.sendUsageMessage(sender);
|
default -> this.sendUsageMessage(sender);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -17,19 +17,21 @@ import static emu.grasscutter.Grasscutter.*;
|
|||||||
public class ConfigContainer {
|
public class ConfigContainer {
|
||||||
/*
|
/*
|
||||||
* Configuration changes:
|
* Configuration changes:
|
||||||
* Version 5 - 'questing' has been changed from a boolean
|
* Version 5 - 'questing' has been changed from a boolean
|
||||||
* to a container of options ('questOptions').
|
* to a container of options ('questOptions').
|
||||||
* This field will be removed in future versions.
|
* This field will be removed in future versions.
|
||||||
* Version 6 - 'questing' has been fully replaced with 'questOptions'.
|
* Version 6 - 'questing' has been fully replaced with 'questOptions'.
|
||||||
* The field for 'legacyResources' has been removed.
|
* The field for 'legacyResources' has been removed.
|
||||||
* Version 7 - 'regionKey' is being added for authentication
|
* Version 7 - 'regionKey' is being added for authentication
|
||||||
* with the new dispatch server.
|
* with the new dispatch server.
|
||||||
* Version 8 - 'server' is being added for enforcing handbook server
|
* Version 8 - 'server' is being added for enforcing handbook server
|
||||||
* addresses.
|
* addresses.
|
||||||
* Version 9 - 'limits' was added for handbook requests.
|
* Version 9 - 'limits' was added for handbook requests.
|
||||||
|
* Version 10 - 'trialCostumes' was added for enabling costumes
|
||||||
|
* on trial avatars.
|
||||||
*/
|
*/
|
||||||
private static int version() {
|
private static int version() {
|
||||||
return 9;
|
return 10;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -255,6 +257,8 @@ public class ConfigContainer {
|
|||||||
public boolean staminaUsage = true;
|
public boolean staminaUsage = true;
|
||||||
public boolean energyUsage = true;
|
public boolean energyUsage = true;
|
||||||
public boolean fishhookTeleport = true;
|
public boolean fishhookTeleport = true;
|
||||||
|
public boolean trialCostumes = false;
|
||||||
|
|
||||||
@SerializedName(value = "questing", alternate = "questOptions")
|
@SerializedName(value = "questing", alternate = "questOptions")
|
||||||
public Questing questing = new Questing();
|
public Questing questing = new Questing();
|
||||||
public ResinOptions resinOptions = new ResinOptions();
|
public ResinOptions resinOptions = new ResinOptions();
|
||||||
|
@ -87,7 +87,10 @@ public class AbilityData {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void initializeModifiers() {
|
private void initializeModifiers() {
|
||||||
if (modifiers == null) return;
|
if (modifiers == null) {
|
||||||
|
this.modifiers = new HashMap<>();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
var _modifiers =
|
var _modifiers =
|
||||||
modifiers.entrySet().stream()
|
modifiers.entrySet().stream()
|
||||||
|
@ -1,12 +1,11 @@
|
|||||||
package emu.grasscutter.data.excels;
|
package emu.grasscutter.data.excels;
|
||||||
|
|
||||||
import com.google.gson.annotations.SerializedName;
|
import com.google.gson.annotations.SerializedName;
|
||||||
import emu.grasscutter.data.GameResource;
|
import emu.grasscutter.data.*;
|
||||||
import emu.grasscutter.data.ResourceType;
|
|
||||||
import emu.grasscutter.game.talk.TalkExec;
|
import emu.grasscutter.game.talk.TalkExec;
|
||||||
|
import lombok.*;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import lombok.Data;
|
|
||||||
import lombok.EqualsAndHashCode;
|
|
||||||
|
|
||||||
@ResourceType(name = "TalkExcelConfigData.json")
|
@ResourceType(name = "TalkExcelConfigData.json")
|
||||||
@EqualsAndHashCode(callSuper = false)
|
@EqualsAndHashCode(callSuper = false)
|
||||||
@ -38,6 +37,14 @@ public final class TalkConfigData extends GameResource {
|
|||||||
this.finishExec == null
|
this.finishExec == null
|
||||||
? List.of()
|
? List.of()
|
||||||
: this.finishExec.stream().filter(x -> x.getType() != null).toList();
|
: this.finishExec.stream().filter(x -> x.getType() != null).toList();
|
||||||
|
|
||||||
|
if (this.questId <= 0) {
|
||||||
|
var id = String.valueOf(this.getId());
|
||||||
|
this.questId = Integer.parseInt(
|
||||||
|
id.length() < 5 ? "0" :
|
||||||
|
id.substring(0, 3)
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Data
|
@Data
|
||||||
|
@ -1,12 +1,8 @@
|
|||||||
package emu.grasscutter.database;
|
package emu.grasscutter.database;
|
||||||
|
|
||||||
import static com.mongodb.client.model.Filters.eq;
|
import dev.morphia.query.*;
|
||||||
|
|
||||||
import dev.morphia.query.FindOptions;
|
|
||||||
import dev.morphia.query.Sort;
|
|
||||||
import dev.morphia.query.experimental.filters.Filters;
|
import dev.morphia.query.experimental.filters.Filters;
|
||||||
import emu.grasscutter.GameConstants;
|
import emu.grasscutter.*;
|
||||||
import emu.grasscutter.Grasscutter;
|
|
||||||
import emu.grasscutter.game.Account;
|
import emu.grasscutter.game.Account;
|
||||||
import emu.grasscutter.game.achievement.Achievements;
|
import emu.grasscutter.game.achievement.Achievements;
|
||||||
import emu.grasscutter.game.activity.PlayerActivityData;
|
import emu.grasscutter.game.activity.PlayerActivityData;
|
||||||
@ -23,12 +19,16 @@ import emu.grasscutter.game.quest.GameMainQuest;
|
|||||||
import emu.grasscutter.game.world.SceneGroupInstance;
|
import emu.grasscutter.game.world.SceneGroupInstance;
|
||||||
import emu.grasscutter.utils.objects.Returnable;
|
import emu.grasscutter.utils.objects.Returnable;
|
||||||
import io.netty.util.concurrent.FastThreadLocalThread;
|
import io.netty.util.concurrent.FastThreadLocalThread;
|
||||||
|
import lombok.Getter;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.concurrent.*;
|
import java.util.concurrent.*;
|
||||||
import java.util.stream.Stream;
|
import java.util.stream.Stream;
|
||||||
|
|
||||||
|
import static com.mongodb.client.model.Filters.eq;
|
||||||
|
|
||||||
public final class DatabaseHelper {
|
public final class DatabaseHelper {
|
||||||
private static final ExecutorService eventExecutor =
|
@Getter private static final ExecutorService eventExecutor =
|
||||||
new ThreadPoolExecutor(
|
new ThreadPoolExecutor(
|
||||||
6,
|
6,
|
||||||
6,
|
6,
|
||||||
|
@ -1,7 +1,5 @@
|
|||||||
package emu.grasscutter.game.avatar;
|
package emu.grasscutter.game.avatar;
|
||||||
|
|
||||||
import static emu.grasscutter.config.Configuration.GAME_OPTIONS;
|
|
||||||
|
|
||||||
import dev.morphia.annotations.*;
|
import dev.morphia.annotations.*;
|
||||||
import emu.grasscutter.GameConstants;
|
import emu.grasscutter.GameConstants;
|
||||||
import emu.grasscutter.data.GameData;
|
import emu.grasscutter.data.GameData;
|
||||||
@ -32,12 +30,15 @@ import emu.grasscutter.net.proto.TrialAvatarInfoOuterClass.TrialAvatarInfo;
|
|||||||
import emu.grasscutter.server.packet.send.*;
|
import emu.grasscutter.server.packet.send.*;
|
||||||
import emu.grasscutter.utils.helpers.ProtoHelper;
|
import emu.grasscutter.utils.helpers.ProtoHelper;
|
||||||
import it.unimi.dsi.fastutil.ints.*;
|
import it.unimi.dsi.fastutil.ints.*;
|
||||||
import java.util.*;
|
|
||||||
import java.util.stream.Stream;
|
|
||||||
import javax.annotation.*;
|
|
||||||
import lombok.*;
|
import lombok.*;
|
||||||
import org.bson.types.ObjectId;
|
import org.bson.types.ObjectId;
|
||||||
|
|
||||||
|
import javax.annotation.*;
|
||||||
|
import java.util.*;
|
||||||
|
import java.util.stream.Stream;
|
||||||
|
|
||||||
|
import static emu.grasscutter.config.Configuration.GAME_OPTIONS;
|
||||||
|
|
||||||
@Entity(value = "avatars", useDiscriminator = false)
|
@Entity(value = "avatars", useDiscriminator = false)
|
||||||
public class Avatar {
|
public class Avatar {
|
||||||
@Transient @Getter private final Int2ObjectMap<GameItem> equips;
|
@Transient @Getter private final Int2ObjectMap<GameItem> equips;
|
||||||
@ -1243,13 +1244,15 @@ public class Avatar {
|
|||||||
});
|
});
|
||||||
|
|
||||||
// Add costume if avatar has a costume.
|
// Add costume if avatar has a costume.
|
||||||
GameData.getAvatarCostumeDataItemIdMap()
|
if (GAME_OPTIONS.trialCostumes) {
|
||||||
|
GameData.getAvatarCostumeDataItemIdMap()
|
||||||
.values()
|
.values()
|
||||||
.forEach(
|
.forEach(
|
||||||
costumeData -> {
|
costumeData -> {
|
||||||
if (costumeData.getCharacterId() != this.getAvatarId()) return;
|
if (costumeData.getCharacterId() != this.getAvatarId()) return;
|
||||||
this.setCostume(costumeData.getId());
|
this.setCostume(costumeData.getId());
|
||||||
});
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Equips the items applied from {@link Avatar#applyTrialItems()}. */
|
/** Equips the items applied from {@link Avatar#applyTrialItems()}. */
|
||||||
|
@ -75,6 +75,7 @@ public class GadgetChest extends GadgetContent {
|
|||||||
} else if (chest.chest_drop_id != 0) {
|
} else if (chest.chest_drop_id != 0) {
|
||||||
status = dropSystem.handleChestDrop(chest.chest_drop_id, chest.drop_count, getGadget());
|
status = dropSystem.handleChestDrop(chest.chest_drop_id, chest.drop_count, getGadget());
|
||||||
}
|
}
|
||||||
|
|
||||||
if (status) {
|
if (status) {
|
||||||
getGadget().updateState(ScriptGadgetState.ChestOpened);
|
getGadget().updateState(ScriptGadgetState.ChestOpened);
|
||||||
player.sendPacket(
|
player.sendPacket(
|
||||||
|
@ -317,7 +317,9 @@ public class StaminaManager extends BasePlayerManager {
|
|||||||
entity.getWorld().broadcastPacket(new PacketEntityFightPropUpdateNotify(entity, FightProperty.FIGHT_PROP_CUR_HP));
|
entity.getWorld().broadcastPacket(new PacketEntityFightPropUpdateNotify(entity, FightProperty.FIGHT_PROP_CUR_HP));
|
||||||
entity.getWorld().broadcastPacket(new PacketLifeStateChangeNotify(0, entity, LifeState.LIFE_DEAD));
|
entity.getWorld().broadcastPacket(new PacketLifeStateChangeNotify(0, entity, LifeState.LIFE_DEAD));
|
||||||
player.getScene().removeEntity(entity);
|
player.getScene().removeEntity(entity);
|
||||||
((EntityAvatar) entity).onDeath(dieType, 0);
|
|
||||||
|
if (entity instanceof EntityAvatar avatar)
|
||||||
|
avatar.onDeath(dieType, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void startSustainedStaminaHandler() {
|
public void startSustainedStaminaHandler() {
|
||||||
|
@ -345,8 +345,9 @@ public class Player implements PlayerHook, FieldFetch {
|
|||||||
this.playerGameTime = gameTime;
|
this.playerGameTime = gameTime;
|
||||||
|
|
||||||
// If the player is the host of the world, update the game time as well.
|
// If the player is the host of the world, update the game time as well.
|
||||||
if (this.getWorld().getHost() == this) {
|
var world = this.getWorld();
|
||||||
this.getWorld().changeTime(gameTime);
|
if (world != null && world.getHost() == this) {
|
||||||
|
world.changeTime(gameTime);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Trigger the script event for game time update.
|
// Trigger the script event for game time update.
|
||||||
@ -707,14 +708,16 @@ public class Player implements PlayerHook, FieldFetch {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void onEnterRegion(SceneRegion region) {
|
public void onEnterRegion(SceneRegion region) {
|
||||||
|
var enterRegionName = "ENTER_REGION_" + region.config_id;
|
||||||
this.getQuestManager().forEachActiveQuest(quest -> {
|
this.getQuestManager().forEachActiveQuest(quest -> {
|
||||||
if (quest.getTriggerData() != null &&
|
if (quest.getTriggerData() != null &&
|
||||||
quest.getTriggers().containsKey("ENTER_REGION_"+ region.config_id)) {
|
quest.getTriggers().containsKey(enterRegionName) &&
|
||||||
|
region.getGroupId() == quest.getTriggerData().get(enterRegionName).getGroupId()) {
|
||||||
// If trigger hasn't been fired yet
|
// If trigger hasn't been fired yet
|
||||||
if (!Boolean.TRUE.equals(quest.getTriggers().put("ENTER_REGION_" + region.config_id, true))) {
|
if (!Boolean.TRUE.equals(quest.getTriggers().put(enterRegionName, true))) {
|
||||||
this.getSession().send(new PacketServerCondMeetQuestListUpdateNotify());
|
this.getSession().send(new PacketServerCondMeetQuestListUpdateNotify());
|
||||||
this.getQuestManager().queueEvent(QuestContent.QUEST_CONTENT_TRIGGER_FIRE,
|
this.getQuestManager().queueEvent(QuestContent.QUEST_CONTENT_TRIGGER_FIRE,
|
||||||
quest.getTriggerData().get("ENTER_REGION_" + region.config_id).getId(), 0);
|
quest.getTriggerData().get(enterRegionName).getId(), 0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@ -722,13 +725,15 @@ public class Player implements PlayerHook, FieldFetch {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void onLeaveRegion(SceneRegion region) {
|
public void onLeaveRegion(SceneRegion region) {
|
||||||
|
var leaveRegionName = "LEAVE_REGION_" + region.config_id;
|
||||||
this.getQuestManager().forEachActiveQuest(quest -> {
|
this.getQuestManager().forEachActiveQuest(quest -> {
|
||||||
if (quest.getTriggers().containsKey("LEAVE_REGION_" + region.config_id)) {
|
if (quest.getTriggers().containsKey(leaveRegionName) &&
|
||||||
|
region.getGroupId() == quest.getTriggerData().get(leaveRegionName).getGroupId()) {
|
||||||
// If trigger hasn't been fired yet
|
// If trigger hasn't been fired yet
|
||||||
if (!Boolean.TRUE.equals(quest.getTriggers().put("LEAVE_REGION_" + region.config_id, true))) {
|
if (!Boolean.TRUE.equals(quest.getTriggers().put(leaveRegionName, true))) {
|
||||||
this.getSession().send(new PacketServerCondMeetQuestListUpdateNotify());
|
this.getSession().send(new PacketServerCondMeetQuestListUpdateNotify());
|
||||||
this.getQuestManager().queueEvent(QuestContent.QUEST_CONTENT_TRIGGER_FIRE,
|
this.getQuestManager().queueEvent(QuestContent.QUEST_CONTENT_TRIGGER_FIRE,
|
||||||
quest.getTriggerData().get("LEAVE_REGION_" + region.config_id).getId(), 0);
|
quest.getTriggerData().get(leaveRegionName).getId(), 0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -1,12 +1,12 @@
|
|||||||
package emu.grasscutter.game.player;
|
package emu.grasscutter.game.player;
|
||||||
|
|
||||||
import static emu.grasscutter.config.Configuration.GAME_OPTIONS;
|
|
||||||
|
|
||||||
import dev.morphia.annotations.Entity;
|
import dev.morphia.annotations.Entity;
|
||||||
import emu.grasscutter.game.avatar.Avatar;
|
import emu.grasscutter.game.avatar.Avatar;
|
||||||
import emu.grasscutter.net.proto.AvatarTeamOuterClass.AvatarTeam;
|
import emu.grasscutter.net.proto.AvatarTeamOuterClass.AvatarTeam;
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.List;
|
import java.util.*;
|
||||||
|
|
||||||
|
import static emu.grasscutter.config.Configuration.GAME_OPTIONS;
|
||||||
|
|
||||||
@Entity
|
@Entity
|
||||||
public final class TeamInfo {
|
public final class TeamInfo {
|
||||||
@ -87,6 +87,8 @@ public final class TeamInfo {
|
|||||||
|
|
||||||
for (int i = 0; i < this.getAvatars().size(); i++) {
|
for (int i = 0; i < this.getAvatars().size(); i++) {
|
||||||
Avatar avatar = player.getAvatars().getAvatarById(this.getAvatars().get(i));
|
Avatar avatar = player.getAvatars().getAvatarById(this.getAvatars().get(i));
|
||||||
|
if (avatar == null) continue;
|
||||||
|
|
||||||
avatarTeam.addAvatarGuidList(avatar.getGuid());
|
avatarTeam.addAvatarGuidList(avatar.getGuid());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -16,11 +16,12 @@ import emu.grasscutter.net.proto.ChildQuestOuterClass.ChildQuest;
|
|||||||
import emu.grasscutter.net.proto.ParentQuestOuterClass.ParentQuest;
|
import emu.grasscutter.net.proto.ParentQuestOuterClass.ParentQuest;
|
||||||
import emu.grasscutter.server.packet.send.*;
|
import emu.grasscutter.server.packet.send.*;
|
||||||
import emu.grasscutter.utils.ConversionUtils;
|
import emu.grasscutter.utils.ConversionUtils;
|
||||||
import java.util.*;
|
|
||||||
import java.util.stream.Collectors;
|
|
||||||
import lombok.*;
|
import lombok.*;
|
||||||
import org.bson.types.ObjectId;
|
import org.bson.types.ObjectId;
|
||||||
|
|
||||||
|
import java.util.*;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
@Entity(value = "quests", useDiscriminator = false)
|
@Entity(value = "quests", useDiscriminator = false)
|
||||||
public class GameMainQuest {
|
public class GameMainQuest {
|
||||||
@Id private ObjectId id;
|
@Id private ObjectId id;
|
||||||
@ -314,7 +315,7 @@ public class GameMainQuest {
|
|||||||
0, new Position(avatarPosPos.get(0), avatarPosPos.get(1), avatarPosPos.get(2))); // position
|
0, new Position(avatarPosPos.get(0), avatarPosPos.get(1), avatarPosPos.get(2))); // position
|
||||||
posAndRot.add(
|
posAndRot.add(
|
||||||
1, new Position(avatarPosRot.get(0), avatarPosRot.get(1), avatarPosRot.get(2))); // rotation
|
1, new Position(avatarPosRot.get(0), avatarPosRot.get(1), avatarPosRot.get(2))); // rotation
|
||||||
Grasscutter.getLogger().info("Succesfully loaded rewind data for subQuest {}", subId);
|
Grasscutter.getLogger().debug("Successfully loaded rewind data for quest {}.", subId);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -15,10 +15,11 @@ import emu.grasscutter.scripts.data.SceneGroup;
|
|||||||
import emu.grasscutter.server.packet.send.*;
|
import emu.grasscutter.server.packet.send.*;
|
||||||
import emu.grasscutter.utils.Utils;
|
import emu.grasscutter.utils.Utils;
|
||||||
import it.unimi.dsi.fastutil.ints.IntIntImmutablePair;
|
import it.unimi.dsi.fastutil.ints.IntIntImmutablePair;
|
||||||
import java.util.*;
|
|
||||||
import javax.script.Bindings;
|
|
||||||
import lombok.*;
|
import lombok.*;
|
||||||
|
|
||||||
|
import javax.script.Bindings;
|
||||||
|
import java.util.*;
|
||||||
|
|
||||||
@Entity
|
@Entity
|
||||||
public class GameQuest {
|
public class GameQuest {
|
||||||
@Transient @Getter @Setter private GameMainQuest mainQuest;
|
@Transient @Getter @Setter private GameMainQuest mainQuest;
|
||||||
@ -142,7 +143,7 @@ public class GameQuest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void setFinishProgress(int index, int value) {
|
public void setFinishProgress(int index, int value) {
|
||||||
finishProgressList[index] = value;
|
this.finishProgressList[index] = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setFailProgress(int index, int value) {
|
public void setFailProgress(int index, int value) {
|
||||||
|
@ -111,7 +111,9 @@ public class QuestManager extends BasePlayerManager {
|
|||||||
30700, // Quest which is responsible for unlocking Crash Course.
|
30700, // Quest which is responsible for unlocking Crash Course.
|
||||||
30800, // Quest which is responsible for unlocking Sparks Amongst the Pages.
|
30800, // Quest which is responsible for unlocking Sparks Amongst the Pages.
|
||||||
|
|
||||||
47001, 47002, 47003, 47004
|
47001, 47002, 47003, 47004,
|
||||||
|
|
||||||
|
2010103, 2010144 // Prologue Act 2: Chasing Shadows
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,12 +1,11 @@
|
|||||||
package emu.grasscutter.game.quest.content;
|
package emu.grasscutter.game.quest.content;
|
||||||
|
|
||||||
import static emu.grasscutter.game.quest.enums.QuestContent.QUEST_CONTENT_COMPLETE_TALK;
|
|
||||||
|
|
||||||
import emu.grasscutter.data.excels.quest.QuestData;
|
import emu.grasscutter.data.excels.quest.QuestData;
|
||||||
import emu.grasscutter.game.quest.GameQuest;
|
import emu.grasscutter.game.quest.*;
|
||||||
import emu.grasscutter.game.quest.QuestValueContent;
|
|
||||||
import lombok.val;
|
import lombok.val;
|
||||||
|
|
||||||
|
import static emu.grasscutter.game.quest.enums.QuestContent.QUEST_CONTENT_COMPLETE_TALK;
|
||||||
|
|
||||||
@QuestValueContent(QUEST_CONTENT_COMPLETE_TALK)
|
@QuestValueContent(QUEST_CONTENT_COMPLETE_TALK)
|
||||||
public class ContentCompleteTalk extends BaseContent {
|
public class ContentCompleteTalk extends BaseContent {
|
||||||
@Override
|
@Override
|
||||||
|
@ -53,7 +53,8 @@ public class ExecNotifyGroupLua extends QuestExecHandler {
|
|||||||
? EventType.EVENT_QUEST_FINISH
|
? EventType.EVENT_QUEST_FINISH
|
||||||
: EventType.EVENT_QUEST_START;
|
: EventType.EVENT_QUEST_START;
|
||||||
scriptManager.callEvent(
|
scriptManager.callEvent(
|
||||||
new ScriptArgs(groupId, eventType, quest.getSubQuestId())
|
new ScriptArgs(groupId, eventType, quest.getSubQuestId(),
|
||||||
|
quest.getState() == QuestState.QUEST_STATE_FINISHED ? 1 : 0)
|
||||||
.setEventSource(quest.getSubQuestId()));
|
.setEventSource(quest.getSubQuestId()));
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -1,15 +1,13 @@
|
|||||||
package emu.grasscutter.game.talk;
|
package emu.grasscutter.game.talk;
|
||||||
|
|
||||||
import static emu.grasscutter.game.quest.enums.QuestCond.QUEST_COND_COMPLETE_TALK;
|
|
||||||
import static emu.grasscutter.game.quest.enums.QuestContent.QUEST_CONTENT_COMPLETE_ANY_TALK;
|
|
||||||
import static emu.grasscutter.game.quest.enums.QuestContent.QUEST_CONTENT_COMPLETE_TALK;
|
|
||||||
|
|
||||||
import emu.grasscutter.data.GameData;
|
import emu.grasscutter.data.GameData;
|
||||||
import emu.grasscutter.data.binout.MainQuestData.TalkData;
|
import emu.grasscutter.data.binout.MainQuestData.TalkData;
|
||||||
import emu.grasscutter.game.player.BasePlayerManager;
|
import emu.grasscutter.game.player.*;
|
||||||
import emu.grasscutter.game.player.Player;
|
|
||||||
import lombok.NonNull;
|
import lombok.NonNull;
|
||||||
|
|
||||||
|
import static emu.grasscutter.game.quest.enums.QuestCond.QUEST_COND_COMPLETE_TALK;
|
||||||
|
import static emu.grasscutter.game.quest.enums.QuestContent.*;
|
||||||
|
|
||||||
public final class TalkManager extends BasePlayerManager {
|
public final class TalkManager extends BasePlayerManager {
|
||||||
public TalkManager(@NonNull Player player) {
|
public TalkManager(@NonNull Player player) {
|
||||||
super(player);
|
super(player);
|
||||||
@ -22,30 +20,31 @@ public final class TalkManager extends BasePlayerManager {
|
|||||||
* @param npcEntityId The entity ID of the NPC being talked to.
|
* @param npcEntityId The entity ID of the NPC being talked to.
|
||||||
*/
|
*/
|
||||||
public void triggerTalkAction(int talkId, int npcEntityId) {
|
public void triggerTalkAction(int talkId, int npcEntityId) {
|
||||||
var talkData = GameData.getTalkConfigDataMap().get(talkId);
|
|
||||||
if (talkData == null) return;
|
|
||||||
|
|
||||||
var player = this.getPlayer();
|
var player = this.getPlayer();
|
||||||
// Check if the NPC id is valid.
|
|
||||||
var entity = player.getScene().getEntityById(npcEntityId);
|
|
||||||
if (entity != null) {
|
|
||||||
// The config ID of the entity is the NPC's ID.
|
|
||||||
if (!talkData.getNpcId().contains(entity.getConfigId())) return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Execute the talk action on associated handlers.
|
var talkData = GameData.getTalkConfigDataMap().get(talkId);
|
||||||
talkData
|
if (talkData != null) {
|
||||||
|
// Check if the NPC id is valid.
|
||||||
|
var entity = player.getScene().getEntityById(npcEntityId);
|
||||||
|
if (entity != null) {
|
||||||
|
// The config ID of the entity is the NPC's ID.
|
||||||
|
if (!talkData.getNpcId().contains(entity.getConfigId())) return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Execute the talk action on associated handlers.
|
||||||
|
talkData
|
||||||
.getFinishExec()
|
.getFinishExec()
|
||||||
.forEach(e -> player.getServer().getTalkSystem().triggerExec(player, talkData, e));
|
.forEach(e -> player.getServer().getTalkSystem().triggerExec(player, talkData, e));
|
||||||
|
|
||||||
|
// Save the talk value to the quest's data.
|
||||||
|
this.saveTalkToQuest(talkId, talkData.getQuestId());
|
||||||
|
}
|
||||||
|
|
||||||
// Invoke the talking events for quests.
|
// Invoke the talking events for quests.
|
||||||
var questManager = player.getQuestManager();
|
var questManager = player.getQuestManager();
|
||||||
questManager.queueEvent(QUEST_CONTENT_COMPLETE_ANY_TALK, talkId);
|
questManager.queueEvent(QUEST_CONTENT_COMPLETE_ANY_TALK, talkId);
|
||||||
questManager.queueEvent(QUEST_CONTENT_COMPLETE_TALK, talkId);
|
questManager.queueEvent(QUEST_CONTENT_COMPLETE_TALK, talkId);
|
||||||
questManager.queueEvent(QUEST_COND_COMPLETE_TALK, talkId);
|
questManager.queueEvent(QUEST_COND_COMPLETE_TALK, talkId);
|
||||||
|
|
||||||
// Save the talk value to the quest's data.
|
|
||||||
this.saveTalkToQuest(talkId, talkData.getQuestId());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void saveTalkToQuest(int talkId, int mainQuestId) {
|
public void saveTalkToQuest(int talkId, int mainQuestId) {
|
||||||
|
@ -1,54 +1,44 @@
|
|||||||
package emu.grasscutter.game.world;
|
package emu.grasscutter.game.world;
|
||||||
|
|
||||||
import emu.grasscutter.Grasscutter;
|
import emu.grasscutter.Grasscutter;
|
||||||
import emu.grasscutter.data.GameData;
|
import emu.grasscutter.data.*;
|
||||||
import emu.grasscutter.data.GameDepot;
|
|
||||||
import emu.grasscutter.data.binout.SceneNpcBornEntry;
|
import emu.grasscutter.data.binout.SceneNpcBornEntry;
|
||||||
import emu.grasscutter.data.binout.routes.Route;
|
import emu.grasscutter.data.binout.routes.Route;
|
||||||
import emu.grasscutter.data.excels.ItemData;
|
import emu.grasscutter.data.excels.*;
|
||||||
import emu.grasscutter.data.excels.SceneData;
|
|
||||||
import emu.grasscutter.data.excels.codex.CodexAnimalData;
|
import emu.grasscutter.data.excels.codex.CodexAnimalData;
|
||||||
import emu.grasscutter.data.excels.monster.MonsterData;
|
import emu.grasscutter.data.excels.monster.MonsterData;
|
||||||
import emu.grasscutter.data.excels.world.WorldLevelData;
|
import emu.grasscutter.data.excels.world.WorldLevelData;
|
||||||
import emu.grasscutter.data.server.Grid;
|
import emu.grasscutter.data.server.Grid;
|
||||||
import emu.grasscutter.game.avatar.Avatar;
|
import emu.grasscutter.game.avatar.Avatar;
|
||||||
import emu.grasscutter.game.dungeons.DungeonManager;
|
import emu.grasscutter.game.dungeons.*;
|
||||||
import emu.grasscutter.game.dungeons.DungeonSettleListener;
|
|
||||||
import emu.grasscutter.game.dungeons.challenge.WorldChallenge;
|
import emu.grasscutter.game.dungeons.challenge.WorldChallenge;
|
||||||
import emu.grasscutter.game.dungeons.enums.DungeonPassConditionType;
|
import emu.grasscutter.game.dungeons.enums.DungeonPassConditionType;
|
||||||
import emu.grasscutter.game.entity.*;
|
import emu.grasscutter.game.entity.*;
|
||||||
import emu.grasscutter.game.entity.gadget.GadgetWorktop;
|
import emu.grasscutter.game.entity.gadget.GadgetWorktop;
|
||||||
import emu.grasscutter.game.inventory.GameItem;
|
import emu.grasscutter.game.inventory.GameItem;
|
||||||
import emu.grasscutter.game.managers.blossom.BlossomManager;
|
import emu.grasscutter.game.managers.blossom.BlossomManager;
|
||||||
import emu.grasscutter.game.player.Player;
|
import emu.grasscutter.game.player.*;
|
||||||
import emu.grasscutter.game.player.TeamInfo;
|
|
||||||
import emu.grasscutter.game.props.*;
|
import emu.grasscutter.game.props.*;
|
||||||
import emu.grasscutter.game.quest.QuestGroupSuite;
|
import emu.grasscutter.game.quest.QuestGroupSuite;
|
||||||
import emu.grasscutter.game.world.data.TeleportProperties;
|
import emu.grasscutter.game.world.data.TeleportProperties;
|
||||||
import emu.grasscutter.net.packet.BasePacket;
|
import emu.grasscutter.net.packet.BasePacket;
|
||||||
import emu.grasscutter.net.proto.AttackResultOuterClass.AttackResult;
|
import emu.grasscutter.net.proto.AttackResultOuterClass.AttackResult;
|
||||||
import emu.grasscutter.net.proto.EnterTypeOuterClass;
|
import emu.grasscutter.net.proto.*;
|
||||||
import emu.grasscutter.net.proto.SelectWorktopOptionReqOuterClass;
|
|
||||||
import emu.grasscutter.net.proto.VisionTypeOuterClass.VisionType;
|
import emu.grasscutter.net.proto.VisionTypeOuterClass.VisionType;
|
||||||
import emu.grasscutter.scripts.SceneIndexManager;
|
import emu.grasscutter.scripts.*;
|
||||||
import emu.grasscutter.scripts.SceneScriptManager;
|
|
||||||
import emu.grasscutter.scripts.constants.EventType;
|
import emu.grasscutter.scripts.constants.EventType;
|
||||||
import emu.grasscutter.scripts.data.SceneBlock;
|
import emu.grasscutter.scripts.data.*;
|
||||||
import emu.grasscutter.scripts.data.SceneGroup;
|
|
||||||
import emu.grasscutter.scripts.data.ScriptArgs;
|
|
||||||
import emu.grasscutter.server.event.entity.EntityCreationEvent;
|
import emu.grasscutter.server.event.entity.EntityCreationEvent;
|
||||||
import emu.grasscutter.server.event.player.PlayerTeleportEvent;
|
import emu.grasscutter.server.event.player.PlayerTeleportEvent;
|
||||||
import emu.grasscutter.server.packet.send.*;
|
import emu.grasscutter.server.packet.send.*;
|
||||||
import emu.grasscutter.utils.objects.KahnsSort;
|
import emu.grasscutter.utils.objects.KahnsSort;
|
||||||
import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
|
import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
|
||||||
import java.util.*;
|
import lombok.*;
|
||||||
import java.util.concurrent.ConcurrentHashMap;
|
|
||||||
import java.util.concurrent.CopyOnWriteArrayList;
|
|
||||||
import java.util.stream.Collectors;
|
|
||||||
import javax.annotation.Nullable;
|
import javax.annotation.Nullable;
|
||||||
import lombok.Getter;
|
import java.util.*;
|
||||||
import lombok.Setter;
|
import java.util.concurrent.*;
|
||||||
import lombok.val;
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
public final class Scene {
|
public final class Scene {
|
||||||
@Getter private final World world;
|
@Getter private final World world;
|
||||||
|
@ -1,17 +1,18 @@
|
|||||||
package emu.grasscutter.plugin;
|
package emu.grasscutter.plugin;
|
||||||
|
|
||||||
import static emu.grasscutter.utils.lang.Language.translate;
|
|
||||||
|
|
||||||
import emu.grasscutter.Grasscutter;
|
import emu.grasscutter.Grasscutter;
|
||||||
import emu.grasscutter.server.event.*;
|
import emu.grasscutter.server.event.*;
|
||||||
import emu.grasscutter.utils.*;
|
import emu.grasscutter.utils.*;
|
||||||
|
import lombok.*;
|
||||||
|
|
||||||
|
import javax.annotation.Nullable;
|
||||||
import java.io.*;
|
import java.io.*;
|
||||||
import java.lang.reflect.Method;
|
import java.lang.reflect.Method;
|
||||||
import java.net.*;
|
import java.net.*;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
import java.util.jar.*;
|
import java.util.jar.*;
|
||||||
import javax.annotation.Nullable;
|
|
||||||
import lombok.*;
|
import static emu.grasscutter.utils.lang.Language.translate;
|
||||||
|
|
||||||
/** Manages the server's plugins and the event system. */
|
/** Manages the server's plugins and the event system. */
|
||||||
public final class PluginManager {
|
public final class PluginManager {
|
||||||
@ -216,9 +217,14 @@ public final class PluginManager {
|
|||||||
Grasscutter.getLogger().info(translate("plugin.enabling_plugin", name));
|
Grasscutter.getLogger().info(translate("plugin.enabling_plugin", name));
|
||||||
try {
|
try {
|
||||||
plugin.onEnable();
|
plugin.onEnable();
|
||||||
|
return;
|
||||||
|
} catch (NoSuchMethodError ignored) {
|
||||||
|
Grasscutter.getLogger().error(translate("plugin.invalid_api.outdated", name));
|
||||||
} catch (Throwable exception) {
|
} catch (Throwable exception) {
|
||||||
Grasscutter.getLogger().error(translate("plugin.enabling_failed", name), exception);
|
Grasscutter.getLogger().error(translate("plugin.enabling_failed", name), exception);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
this.disablePlugin(plugin);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,7 +1,5 @@
|
|||||||
package emu.grasscutter.scripts;
|
package emu.grasscutter.scripts;
|
||||||
|
|
||||||
import static emu.grasscutter.scripts.constants.EventType.EVENT_TIMER_EVENT;
|
|
||||||
|
|
||||||
import com.github.davidmoten.rtreemulti.RTree;
|
import com.github.davidmoten.rtreemulti.RTree;
|
||||||
import com.github.davidmoten.rtreemulti.geometry.Geometry;
|
import com.github.davidmoten.rtreemulti.geometry.Geometry;
|
||||||
import emu.grasscutter.Grasscutter;
|
import emu.grasscutter.Grasscutter;
|
||||||
@ -21,17 +19,20 @@ import emu.grasscutter.server.packet.send.PacketGroupSuiteNotify;
|
|||||||
import emu.grasscutter.utils.*;
|
import emu.grasscutter.utils.*;
|
||||||
import io.netty.util.concurrent.FastThreadLocalThread;
|
import io.netty.util.concurrent.FastThreadLocalThread;
|
||||||
import it.unimi.dsi.fastutil.ints.*;
|
import it.unimi.dsi.fastutil.ints.*;
|
||||||
|
import kotlin.Pair;
|
||||||
|
import lombok.val;
|
||||||
|
import org.luaj.vm2.*;
|
||||||
|
import org.luaj.vm2.lib.jse.CoerceJavaToLua;
|
||||||
|
|
||||||
|
import javax.annotation.*;
|
||||||
import java.io.*;
|
import java.io.*;
|
||||||
import java.nio.file.Files;
|
import java.nio.file.Files;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
import java.util.concurrent.*;
|
import java.util.concurrent.*;
|
||||||
import java.util.concurrent.atomic.AtomicInteger;
|
import java.util.concurrent.atomic.AtomicInteger;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
import javax.annotation.*;
|
|
||||||
import kotlin.Pair;
|
import static emu.grasscutter.scripts.constants.EventType.EVENT_TIMER_EVENT;
|
||||||
import lombok.val;
|
|
||||||
import org.luaj.vm2.*;
|
|
||||||
import org.luaj.vm2.lib.jse.CoerceJavaToLua;
|
|
||||||
|
|
||||||
public class SceneScriptManager {
|
public class SceneScriptManager {
|
||||||
private final Scene scene;
|
private final Scene scene;
|
||||||
@ -801,26 +802,26 @@ public class SceneScriptManager {
|
|||||||
private void realCallEvent(@Nonnull ScriptArgs params) {
|
private void realCallEvent(@Nonnull ScriptArgs params) {
|
||||||
try {
|
try {
|
||||||
ScriptLoader.getScriptLib().setSceneScriptManager(this);
|
ScriptLoader.getScriptLib().setSceneScriptManager(this);
|
||||||
int eventType = params.type;
|
|
||||||
Set<SceneTrigger> relevantTriggers = new HashSet<>();
|
var eventType = params.type;
|
||||||
if (eventType == EventType.EVENT_ENTER_REGION || eventType == EventType.EVENT_LEAVE_REGION) {
|
var relevantTriggers = switch (eventType) {
|
||||||
relevantTriggers =
|
case EventType.EVENT_ENTER_REGION, EventType.EVENT_LEAVE_REGION ->
|
||||||
this.getTriggersByEvent(eventType).stream()
|
this.getTriggersByEvent(eventType).stream()
|
||||||
.filter(
|
.filter(
|
||||||
t ->
|
t ->
|
||||||
t.getCondition().contains(String.valueOf(params.param1))
|
t.getCondition().contains(String.valueOf(params.param1))
|
||||||
&& (t.getSource().isEmpty()
|
&& (t.getSource().isEmpty()
|
||||||
|| t.getSource().equals(params.getEventSource())))
|
|| t.getSource().equals(params.getEventSource())))
|
||||||
.collect(Collectors.toSet());
|
.collect(Collectors.toSet());
|
||||||
} else {
|
default ->
|
||||||
relevantTriggers =
|
this.getTriggersByEvent(eventType).stream()
|
||||||
this.getTriggersByEvent(eventType).stream()
|
.filter(
|
||||||
.filter(
|
t -> params.getGroupId() == 0 || t.getCurrentGroup().id == params.getGroupId())
|
||||||
t -> params.getGroupId() == 0 || t.getCurrentGroup().id == params.getGroupId())
|
.filter(
|
||||||
.filter(
|
t -> (t.getSource().isEmpty() || t.getSource().equals(params.getEventSource())))
|
||||||
t -> (t.getSource().isEmpty() || t.getSource().equals(params.getEventSource())))
|
.collect(Collectors.toSet());
|
||||||
.collect(Collectors.toSet());
|
};
|
||||||
}
|
|
||||||
for (SceneTrigger trigger : relevantTriggers) {
|
for (SceneTrigger trigger : relevantTriggers) {
|
||||||
handleEventForTrigger(params, trigger);
|
handleEventForTrigger(params, trigger);
|
||||||
}
|
}
|
||||||
|
@ -129,7 +129,7 @@ public class ScriptLib {
|
|||||||
|
|
||||||
public int SetWorktopOptionsByGroupId(int groupId, int configId, int[] options) {
|
public int SetWorktopOptionsByGroupId(int groupId, int configId, int[] options) {
|
||||||
logger.debug("[LUA] Call SetWorktopOptionsByGroupId with {},{},{}",
|
logger.debug("[LUA] Call SetWorktopOptionsByGroupId with {},{},{}",
|
||||||
groupId,configId,options);
|
groupId, configId, options);
|
||||||
|
|
||||||
val entity = getSceneScriptManager().getScene().getEntityByConfigId(configId, groupId);
|
val entity = getSceneScriptManager().getScene().getEntityByConfigId(configId, groupId);
|
||||||
|
|
||||||
|
@ -1,8 +1,5 @@
|
|||||||
package emu.grasscutter.server.game;
|
package emu.grasscutter.server.game;
|
||||||
|
|
||||||
import static emu.grasscutter.config.Configuration.*;
|
|
||||||
import static emu.grasscutter.utils.lang.Language.translate;
|
|
||||||
|
|
||||||
import emu.grasscutter.*;
|
import emu.grasscutter.*;
|
||||||
import emu.grasscutter.Grasscutter.ServerRunMode;
|
import emu.grasscutter.Grasscutter.ServerRunMode;
|
||||||
import emu.grasscutter.database.DatabaseHelper;
|
import emu.grasscutter.database.DatabaseHelper;
|
||||||
@ -32,14 +29,19 @@ import emu.grasscutter.server.event.internal.*;
|
|||||||
import emu.grasscutter.server.event.types.ServerEvent;
|
import emu.grasscutter.server.event.types.ServerEvent;
|
||||||
import emu.grasscutter.server.scheduler.ServerTaskScheduler;
|
import emu.grasscutter.server.scheduler.ServerTaskScheduler;
|
||||||
import emu.grasscutter.task.TaskMap;
|
import emu.grasscutter.task.TaskMap;
|
||||||
import java.net.*;
|
import emu.grasscutter.utils.Utils;
|
||||||
import java.time.*;
|
|
||||||
import java.util.*;
|
|
||||||
import java.util.concurrent.ConcurrentHashMap;
|
|
||||||
import kcp.highway.*;
|
import kcp.highway.*;
|
||||||
import lombok.*;
|
import lombok.*;
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
|
||||||
|
import java.net.*;
|
||||||
|
import java.time.*;
|
||||||
|
import java.util.*;
|
||||||
|
import java.util.concurrent.*;
|
||||||
|
|
||||||
|
import static emu.grasscutter.config.Configuration.*;
|
||||||
|
import static emu.grasscutter.utils.lang.Language.translate;
|
||||||
|
|
||||||
@Getter
|
@Getter
|
||||||
public final class GameServer extends KcpServer implements Iterable<Player> {
|
public final class GameServer extends KcpServer implements Iterable<Player> {
|
||||||
// Game server base
|
// Game server base
|
||||||
@ -326,16 +328,27 @@ public final class GameServer extends KcpServer implements Iterable<Player> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void onServerShutdown() {
|
public void onServerShutdown() {
|
||||||
ServerStopEvent event = new ServerStopEvent(ServerEvent.Type.GAME, OffsetDateTime.now());
|
var event = new ServerStopEvent(ServerEvent.Type.GAME, OffsetDateTime.now());
|
||||||
event.call();
|
event.call();
|
||||||
|
|
||||||
this.getPlayers()
|
this.getPlayers()
|
||||||
.forEach(
|
.forEach(
|
||||||
(uid, player) -> {
|
(uid, player) -> player.getSession().close());
|
||||||
player.getSession().close();
|
|
||||||
});
|
|
||||||
|
|
||||||
this.getWorlds().forEach(World::save);
|
this.getWorlds().forEach(World::save);
|
||||||
|
|
||||||
|
Utils.sleep(1000L); // Wait 1 second for operations to finish.
|
||||||
|
|
||||||
|
try {
|
||||||
|
var threadPool = GameSessionManager.getLogicThread();
|
||||||
|
|
||||||
|
// Shutdown network thread.
|
||||||
|
threadPool.shutdownGracefully();
|
||||||
|
// Wait for the network thread to finish.
|
||||||
|
if (!threadPool.awaitTermination(5, TimeUnit.SECONDS)) {
|
||||||
|
Grasscutter.getLogger().error("Logic thread did not terminate!");
|
||||||
|
}
|
||||||
|
} catch (InterruptedException ignored) { }
|
||||||
}
|
}
|
||||||
|
|
||||||
@NotNull @Override
|
@NotNull @Override
|
||||||
|
@ -1,27 +1,21 @@
|
|||||||
package emu.grasscutter.server.game;
|
package emu.grasscutter.server.game;
|
||||||
|
|
||||||
import static emu.grasscutter.config.Configuration.GAME_INFO;
|
|
||||||
import static emu.grasscutter.config.Configuration.SERVER;
|
|
||||||
import static emu.grasscutter.utils.lang.Language.translate;
|
|
||||||
|
|
||||||
import emu.grasscutter.Grasscutter;
|
import emu.grasscutter.Grasscutter;
|
||||||
import emu.grasscutter.Grasscutter.ServerDebugMode;
|
import emu.grasscutter.Grasscutter.ServerDebugMode;
|
||||||
import emu.grasscutter.game.Account;
|
import emu.grasscutter.game.Account;
|
||||||
import emu.grasscutter.game.player.Player;
|
import emu.grasscutter.game.player.Player;
|
||||||
import emu.grasscutter.net.packet.BasePacket;
|
import emu.grasscutter.net.packet.*;
|
||||||
import emu.grasscutter.net.packet.PacketOpcodes;
|
|
||||||
import emu.grasscutter.net.packet.PacketOpcodesUtils;
|
|
||||||
import emu.grasscutter.server.event.game.SendPacketEvent;
|
import emu.grasscutter.server.event.game.SendPacketEvent;
|
||||||
import emu.grasscutter.utils.Crypto;
|
import emu.grasscutter.utils.*;
|
||||||
import emu.grasscutter.utils.FileUtils;
|
import io.netty.buffer.*;
|
||||||
import emu.grasscutter.utils.Utils;
|
import lombok.*;
|
||||||
import io.netty.buffer.ByteBuf;
|
|
||||||
import io.netty.buffer.Unpooled;
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.net.InetSocketAddress;
|
import java.net.InetSocketAddress;
|
||||||
import java.nio.file.Path;
|
import java.nio.file.Path;
|
||||||
import lombok.Getter;
|
|
||||||
import lombok.Setter;
|
import static emu.grasscutter.config.Configuration.*;
|
||||||
|
import static emu.grasscutter.utils.lang.Language.translate;
|
||||||
|
|
||||||
public class GameSession implements GameSessionManager.KcpChannel {
|
public class GameSession implements GameSessionManager.KcpChannel {
|
||||||
private final GameServer server;
|
private final GameServer server;
|
||||||
@ -139,7 +133,11 @@ public class GameSession implements GameSessionManager.KcpChannel {
|
|||||||
SendPacketEvent event = new SendPacketEvent(this, packet);
|
SendPacketEvent event = new SendPacketEvent(this, packet);
|
||||||
event.call();
|
event.call();
|
||||||
if (!event.isCanceled()) { // If event is not cancelled, continue.
|
if (!event.isCanceled()) { // If event is not cancelled, continue.
|
||||||
tunnel.writeData(event.getPacket().build());
|
try {
|
||||||
|
tunnel.writeData(event.getPacket().build());
|
||||||
|
} catch (Exception ignored) {
|
||||||
|
Grasscutter.getLogger().debug("Unable to send packet to client.");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2,16 +2,16 @@ package emu.grasscutter.server.game;
|
|||||||
|
|
||||||
import emu.grasscutter.Grasscutter;
|
import emu.grasscutter.Grasscutter;
|
||||||
import emu.grasscutter.utils.Utils;
|
import emu.grasscutter.utils.Utils;
|
||||||
import io.netty.buffer.ByteBuf;
|
import io.netty.buffer.*;
|
||||||
import io.netty.buffer.Unpooled;
|
|
||||||
import io.netty.channel.DefaultEventLoop;
|
import io.netty.channel.DefaultEventLoop;
|
||||||
|
import kcp.highway.*;
|
||||||
|
import lombok.Getter;
|
||||||
|
|
||||||
import java.net.InetSocketAddress;
|
import java.net.InetSocketAddress;
|
||||||
import java.util.concurrent.ConcurrentHashMap;
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
import kcp.highway.KcpListener;
|
|
||||||
import kcp.highway.Ukcp;
|
|
||||||
|
|
||||||
public class GameSessionManager {
|
public class GameSessionManager {
|
||||||
private static final DefaultEventLoop logicThread = new DefaultEventLoop();
|
@Getter private static final DefaultEventLoop logicThread = new DefaultEventLoop();
|
||||||
private static final ConcurrentHashMap<Ukcp, GameSession> sessions = new ConcurrentHashMap<>();
|
private static final ConcurrentHashMap<Ukcp, GameSession> sessions = new ConcurrentHashMap<>();
|
||||||
private static final KcpListener listener =
|
private static final KcpListener listener =
|
||||||
new KcpListener() {
|
new KcpListener() {
|
||||||
|
@ -1,15 +1,13 @@
|
|||||||
package emu.grasscutter.server.packet.recv;
|
package emu.grasscutter.server.packet.recv;
|
||||||
|
|
||||||
import emu.grasscutter.data.GameData;
|
import emu.grasscutter.data.GameData;
|
||||||
import emu.grasscutter.data.excels.GadgetData;
|
|
||||||
import emu.grasscutter.data.excels.ItemData;
|
import emu.grasscutter.data.excels.ItemData;
|
||||||
import emu.grasscutter.data.excels.monster.MonsterData;
|
import emu.grasscutter.data.excels.monster.MonsterData;
|
||||||
import emu.grasscutter.game.entity.*;
|
import emu.grasscutter.game.entity.*;
|
||||||
import emu.grasscutter.game.world.Position;
|
import emu.grasscutter.game.world.Position;
|
||||||
import emu.grasscutter.net.packet.Opcodes;
|
import emu.grasscutter.net.packet.*;
|
||||||
import emu.grasscutter.net.packet.PacketHandler;
|
|
||||||
import emu.grasscutter.net.packet.PacketOpcodes;
|
|
||||||
import emu.grasscutter.net.proto.QuestCreateEntityReqOuterClass.QuestCreateEntityReq;
|
import emu.grasscutter.net.proto.QuestCreateEntityReqOuterClass.QuestCreateEntityReq;
|
||||||
|
import emu.grasscutter.scripts.data.SceneGadget;
|
||||||
import emu.grasscutter.server.game.GameSession;
|
import emu.grasscutter.server.game.GameSession;
|
||||||
import emu.grasscutter.server.packet.send.PacketQuestCreateEntityRsp;
|
import emu.grasscutter.server.packet.send.PacketQuestCreateEntityRsp;
|
||||||
import lombok.val;
|
import lombok.val;
|
||||||
@ -30,12 +28,29 @@ public class HandlerQuestCreateEntityReq extends PacketHandler {
|
|||||||
case GADGET_ID -> {
|
case GADGET_ID -> {
|
||||||
val gadgetId = entity.getGadgetId();
|
val gadgetId = entity.getGadgetId();
|
||||||
val gadgetInfo = entity.getGadget();
|
val gadgetInfo = entity.getGadget();
|
||||||
GadgetData gadgetData = GameData.getGadgetDataMap().get(gadgetId);
|
var gadgetData = GameData.getGadgetDataMap().get(gadgetId);
|
||||||
gameEntity =
|
gameEntity =
|
||||||
switch (gadgetData.getType()) {
|
switch (gadgetData.getType()) {
|
||||||
case Vehicle -> new EntityVehicle(scene, session.getPlayer(), gadgetId, 0, pos, rot);
|
case Vehicle -> new EntityVehicle(scene, session.getPlayer(), gadgetId, 0, pos, rot);
|
||||||
|
case Chest -> {
|
||||||
|
var chest = gadgetInfo.getChest();
|
||||||
|
var gadget = new EntityGadget(scene, gadgetId, pos, rot);
|
||||||
|
// Create the gadget data for the chest.
|
||||||
|
var metaGadget = new SceneGadget();
|
||||||
|
metaGadget.drop_count = 1; // TODO: Check if more items should be dropped.
|
||||||
|
metaGadget.chest_drop_id = chest.getChestDropId();
|
||||||
|
metaGadget.setShowcutscene(chest.getIsShowCutscene());
|
||||||
|
// Apply the gadget data to the chest.
|
||||||
|
gadget.setMetaGadget(metaGadget);
|
||||||
|
|
||||||
|
yield gadget;
|
||||||
|
}
|
||||||
default -> new EntityGadget(scene, gadgetId, pos, rot);
|
default -> new EntityGadget(scene, gadgetId, pos, rot);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
if (gameEntity instanceof EntityGadget gadget) {
|
||||||
|
gadget.buildContent();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
case ITEM_ID -> {
|
case ITEM_ID -> {
|
||||||
val itemId = entity.getItemId();
|
val itemId = entity.getItemId();
|
||||||
|
@ -1,8 +1,5 @@
|
|||||||
package emu.grasscutter.utils;
|
package emu.grasscutter.utils;
|
||||||
|
|
||||||
import static emu.grasscutter.utils.FileUtils.getResourcePath;
|
|
||||||
import static emu.grasscutter.utils.lang.Language.translate;
|
|
||||||
|
|
||||||
import emu.grasscutter.Grasscutter;
|
import emu.grasscutter.Grasscutter;
|
||||||
import emu.grasscutter.config.ConfigContainer;
|
import emu.grasscutter.config.ConfigContainer;
|
||||||
import emu.grasscutter.data.DataLoader;
|
import emu.grasscutter.data.DataLoader;
|
||||||
@ -11,15 +8,20 @@ import emu.grasscutter.utils.objects.Returnable;
|
|||||||
import io.javalin.http.Context;
|
import io.javalin.http.Context;
|
||||||
import io.netty.buffer.*;
|
import io.netty.buffer.*;
|
||||||
import it.unimi.dsi.fastutil.ints.*;
|
import it.unimi.dsi.fastutil.ints.*;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
|
||||||
|
import javax.annotation.Nullable;
|
||||||
import java.io.*;
|
import java.io.*;
|
||||||
|
import java.lang.reflect.Field;
|
||||||
import java.nio.charset.StandardCharsets;
|
import java.nio.charset.StandardCharsets;
|
||||||
import java.nio.file.*;
|
import java.nio.file.*;
|
||||||
import java.time.*;
|
import java.time.*;
|
||||||
import java.time.temporal.TemporalAdjusters;
|
import java.time.temporal.TemporalAdjusters;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
import java.util.concurrent.ThreadLocalRandom;
|
import java.util.concurrent.ThreadLocalRandom;
|
||||||
import javax.annotation.Nullable;
|
|
||||||
import org.slf4j.Logger;
|
import static emu.grasscutter.utils.FileUtils.getResourcePath;
|
||||||
|
import static emu.grasscutter.utils.lang.Language.translate;
|
||||||
|
|
||||||
@SuppressWarnings({"UnusedReturnValue", "BooleanMethodIsAlwaysInverted"})
|
@SuppressWarnings({"UnusedReturnValue", "BooleanMethodIsAlwaysInverted"})
|
||||||
public final class Utils {
|
public final class Utils {
|
||||||
@ -484,6 +486,7 @@ public final class Utils {
|
|||||||
*
|
*
|
||||||
* @param runnable The task to run.
|
* @param runnable The task to run.
|
||||||
*/
|
*/
|
||||||
|
@SuppressWarnings("BusyWait")
|
||||||
public static void waitFor(Returnable<Boolean> runnable) {
|
public static void waitFor(Returnable<Boolean> runnable) {
|
||||||
while (!runnable.invoke()) {
|
while (!runnable.invoke()) {
|
||||||
try {
|
try {
|
||||||
@ -493,4 +496,33 @@ public final class Utils {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Recursively finds all fields in a class.
|
||||||
|
*
|
||||||
|
* @param type The class to find fields in.
|
||||||
|
* @return A list of all fields in the class.
|
||||||
|
*/
|
||||||
|
public static List<Field> getAllFields(Class<?> type) {
|
||||||
|
var fields = new LinkedList<>(Arrays.asList(type.getDeclaredFields()));
|
||||||
|
|
||||||
|
// Check for superclasses.
|
||||||
|
if (type.getSuperclass() != null) {
|
||||||
|
fields.addAll(getAllFields(type.getSuperclass()));
|
||||||
|
}
|
||||||
|
|
||||||
|
return fields;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sleeps the current thread without an exception.
|
||||||
|
*
|
||||||
|
* @param millis The amount of milliseconds to sleep.
|
||||||
|
*/
|
||||||
|
public static void sleep(long millis) {
|
||||||
|
try {
|
||||||
|
Thread.sleep(millis);
|
||||||
|
} catch (InterruptedException ignored) {
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,11 +1,11 @@
|
|||||||
package emu.grasscutter.utils.objects;
|
package emu.grasscutter.utils.objects;
|
||||||
|
|
||||||
import com.google.gson.JsonNull;
|
import com.google.gson.*;
|
||||||
import com.google.gson.JsonObject;
|
|
||||||
import emu.grasscutter.server.dispatch.IDispatcher;
|
import emu.grasscutter.server.dispatch.IDispatcher;
|
||||||
|
import emu.grasscutter.utils.Utils;
|
||||||
|
|
||||||
import java.lang.reflect.Field;
|
import java.lang.reflect.Field;
|
||||||
import java.util.Arrays;
|
import java.util.*;
|
||||||
import java.util.HashMap;
|
|
||||||
|
|
||||||
public interface FieldFetch {
|
public interface FieldFetch {
|
||||||
/**
|
/**
|
||||||
@ -18,7 +18,7 @@ public interface FieldFetch {
|
|||||||
// Prepare field properties.
|
// Prepare field properties.
|
||||||
var fieldValues = new JsonObject();
|
var fieldValues = new JsonObject();
|
||||||
var fieldMap = new HashMap<String, Field>();
|
var fieldMap = new HashMap<String, Field>();
|
||||||
Arrays.stream(this.getClass().getDeclaredFields())
|
Utils.getAllFields(this.getClass())
|
||||||
.forEach(field -> fieldMap.put(field.getName(), field));
|
.forEach(field -> fieldMap.put(field.getName(), field));
|
||||||
|
|
||||||
// Find the values of all requested fields.
|
// Find the values of all requested fields.
|
||||||
|
@ -463,7 +463,8 @@
|
|||||||
"disabling_failed": "Failed to disable plugin: %s",
|
"disabling_failed": "Failed to disable plugin: %s",
|
||||||
"invalid_api": {
|
"invalid_api": {
|
||||||
"not_present": "Plugin %s does not specify an API version.",
|
"not_present": "Plugin %s does not specify an API version.",
|
||||||
"lower": "Plugin %s is using API version %s, while the server is using API version %s."
|
"lower": "Plugin %s is using API version %s, while the server is using API version %s.",
|
||||||
|
"outdated": "Plugin %s is using an outdated API method."
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -463,7 +463,8 @@
|
|||||||
"disabling_failed": "Error al desactivar el plugin: %s",
|
"disabling_failed": "Error al desactivar el plugin: %s",
|
||||||
"invalid_api": {
|
"invalid_api": {
|
||||||
"not_present": "🇺🇸Plugin %s does not specify an API version.",
|
"not_present": "🇺🇸Plugin %s does not specify an API version.",
|
||||||
"lower": "🇺🇸Plugin %s is using API version %s, while the server is using API version %s."
|
"lower": "🇺🇸Plugin %s is using API version %s, while the server is using API version %s.",
|
||||||
|
"outdated": "🇺🇸Plugin %s is using an outdated API method."
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -463,7 +463,8 @@
|
|||||||
"disabling_failed": "Impossible de désactiver le plugin %s",
|
"disabling_failed": "Impossible de désactiver le plugin %s",
|
||||||
"invalid_api": {
|
"invalid_api": {
|
||||||
"not_present": "🇺🇸Plugin %s does not specify an API version.",
|
"not_present": "🇺🇸Plugin %s does not specify an API version.",
|
||||||
"lower": "🇺🇸Plugin %s is using API version %s, while the server is using API version %s."
|
"lower": "🇺🇸Plugin %s is using API version %s, while the server is using API version %s.",
|
||||||
|
"outdated": "🇺🇸Plugin %s is using an outdated API method."
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -463,7 +463,8 @@
|
|||||||
"disabling_failed": "Impossibile disabilitare il plug-in: %s",
|
"disabling_failed": "Impossibile disabilitare il plug-in: %s",
|
||||||
"invalid_api": {
|
"invalid_api": {
|
||||||
"not_present": "🇺🇸Plugin %s does not specify an API version.",
|
"not_present": "🇺🇸Plugin %s does not specify an API version.",
|
||||||
"lower": "🇺🇸Plugin %s is using API version %s, while the server is using API version %s."
|
"lower": "🇺🇸Plugin %s is using API version %s, while the server is using API version %s.",
|
||||||
|
"outdated": "🇺🇸Plugin %s is using an outdated API method."
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -463,7 +463,8 @@
|
|||||||
"disabling_failed": "プラグインの無効化に失敗しました: %s",
|
"disabling_failed": "プラグインの無効化に失敗しました: %s",
|
||||||
"invalid_api": {
|
"invalid_api": {
|
||||||
"not_present": "🇺🇸Plugin %s does not specify an API version.",
|
"not_present": "🇺🇸Plugin %s does not specify an API version.",
|
||||||
"lower": "🇺🇸Plugin %s is using API version %s, while the server is using API version %s."
|
"lower": "🇺🇸Plugin %s is using API version %s, while the server is using API version %s.",
|
||||||
|
"outdated": "🇺🇸Plugin %s is using an outdated API method."
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -463,7 +463,8 @@
|
|||||||
"disabling_failed": "플러그인을 비활성화하는데 실패했습니다: %s",
|
"disabling_failed": "플러그인을 비활성화하는데 실패했습니다: %s",
|
||||||
"invalid_api": {
|
"invalid_api": {
|
||||||
"not_present": "🇺🇸Plugin %s does not specify an API version.",
|
"not_present": "🇺🇸Plugin %s does not specify an API version.",
|
||||||
"lower": "🇺🇸Plugin %s is using API version %s, while the server is using API version %s."
|
"lower": "🇺🇸Plugin %s is using API version %s, while the server is using API version %s.",
|
||||||
|
"outdated": "🇺🇸Plugin %s is using an outdated API method."
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -463,7 +463,8 @@
|
|||||||
"disabling_failed": "Nie udało się wyłączyć pluginu: %s",
|
"disabling_failed": "Nie udało się wyłączyć pluginu: %s",
|
||||||
"invalid_api": {
|
"invalid_api": {
|
||||||
"not_present": "🇺🇸Plugin %s does not specify an API version.",
|
"not_present": "🇺🇸Plugin %s does not specify an API version.",
|
||||||
"lower": "🇺🇸Plugin %s is using API version %s, while the server is using API version %s."
|
"lower": "🇺🇸Plugin %s is using API version %s, while the server is using API version %s.",
|
||||||
|
"outdated": "🇺🇸Plugin %s is using an outdated API method."
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -463,7 +463,8 @@
|
|||||||
"disabling_failed": "🇺🇸Failed to disable plugin: %s",
|
"disabling_failed": "🇺🇸Failed to disable plugin: %s",
|
||||||
"invalid_api": {
|
"invalid_api": {
|
||||||
"not_present": "🇺🇸Plugin %s does not specify an API version.",
|
"not_present": "🇺🇸Plugin %s does not specify an API version.",
|
||||||
"lower": "🇺🇸Plugin %s is using API version %s, while the server is using API version %s."
|
"lower": "🇺🇸Plugin %s is using API version %s, while the server is using API version %s.",
|
||||||
|
"outdated": "🇺🇸Plugin %s is using an outdated API method."
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -463,7 +463,8 @@
|
|||||||
"disabling_failed": "Ошибка отключения Плагина: %s",
|
"disabling_failed": "Ошибка отключения Плагина: %s",
|
||||||
"invalid_api": {
|
"invalid_api": {
|
||||||
"not_present": "🇺🇸Plugin %s does not specify an API version.",
|
"not_present": "🇺🇸Plugin %s does not specify an API version.",
|
||||||
"lower": "🇺🇸Plugin %s is using API version %s, while the server is using API version %s."
|
"lower": "🇺🇸Plugin %s is using API version %s, while the server is using API version %s.",
|
||||||
|
"outdated": "🇺🇸Plugin %s is using an outdated API method."
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -463,7 +463,8 @@
|
|||||||
"disabling_failed": "无法禁用插件:%s",
|
"disabling_failed": "无法禁用插件:%s",
|
||||||
"invalid_api": {
|
"invalid_api": {
|
||||||
"not_present": "🇺🇸Plugin %s does not specify an API version.",
|
"not_present": "🇺🇸Plugin %s does not specify an API version.",
|
||||||
"lower": "🇺🇸Plugin %s is using API version %s, while the server is using API version %s."
|
"lower": "🇺🇸Plugin %s is using API version %s, while the server is using API version %s.",
|
||||||
|
"outdated": "🇺🇸Plugin %s is using an outdated API method."
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -463,7 +463,8 @@
|
|||||||
"disabling_failed": "🇺🇸Failed to disable plugin: %s",
|
"disabling_failed": "🇺🇸Failed to disable plugin: %s",
|
||||||
"invalid_api": {
|
"invalid_api": {
|
||||||
"not_present": "🇺🇸Plugin %s does not specify an API version.",
|
"not_present": "🇺🇸Plugin %s does not specify an API version.",
|
||||||
"lower": "🇺🇸Plugin %s is using API version %s, while the server is using API version %s."
|
"lower": "🇺🇸Plugin %s is using API version %s, while the server is using API version %s.",
|
||||||
|
"outdated": "🇺🇸Plugin %s is using an outdated API method."
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user