mirror of
https://github.com/Melledy/Grasscutter.git
synced 2024-11-25 14:04:08 +00:00
Merge branch 'development' into tp
This commit is contained in:
commit
7fdf74986c
@ -113,9 +113,9 @@ There is a dummy user named "Server" in every player's friends list that you can
|
||||
| clearartifacts | clearartifacts | player.clearartifacts | Client only | Deletes all unequipped and unlocked level 0 artifacts, including 5-star rarity ones from your inventory. | clearart |
|
||||
| clearweapons | clearweapons | player.clearweapons | Client only | Deletes all unequipped and unlocked weapons, including 5-star rarity ones from your inventory. | clearwpns |
|
||||
| drop | drop <itemID\|itemName> [amount] | server.drop | Client only | Drops an item around you. | `d` `dropitem` |
|
||||
| give | give [player] <itemId\|itemName> [amount] [level] | player.give | Both side | Gives item(s) to you or the specified player. | `g` `item` `giveitem` |
|
||||
| give | give [player] <itemId\|itemName> [amount] [level] [finement] | player.give | Both side | Gives item(s) to you or the specified player. (finement option only weapon.) | `g` `item` `giveitem` |
|
||||
| givechar | givechar <uid> <avatarId> | player.givechar | Both side | Gives the player a specified character. | givec |
|
||||
| giveall | giveall [uid] [amount] | player.giveall | Both side | Gives all items. | givea |
|
||||
| giveall | giveall [uid] [amount] | player.giveall | Both side | Gives all items. | givea |
|
||||
| godmode | godmode [uid] | player.godmode | Client only | Prevents you from taking damage. | |
|
||||
| heal | heal | player.heal | Client only | Heals all characters in your current team. | h |
|
||||
| help | help [command] | | Both side | Sends the help message or shows information about a specified command. | |
|
||||
|
@ -114,7 +114,7 @@ chmod +x gradlew
|
||||
| clearartifacts | clearartifacts | player.clearartifacts | 仅客户端 | 删除所有未装备及未解锁的圣遗物,包括五星 | clearart |
|
||||
| clearweapons | clearweapons | player.clearweapons | 仅客户端 | 删除所有未装备及未解锁的武器,包括五星 | clearwp |
|
||||
| drop | drop <物品ID\|物品名称> [数量] | server.drop | 仅客户端 | 在指定玩家周围掉落指定物品 | `d` `dropitem` |
|
||||
| give | give [uid] <物品ID\|物品名称> [数量] [等级] | | | 给予指定玩家一定数量及等级的物品 | `g` `item` `giveitem` |
|
||||
| give | give [uid] <物品ID\|物品名称> [数量] [等级] [精炼等级] | | | 给予指定玩家一定数量及等级的物品 (精炼等级仅适用于武器) | `g` `item` `giveitem` |
|
||||
| givechar | givechar <uid> <角色ID> [等级] | player.givechar | 均可使用 | 给予指定玩家对应角色 | givec |
|
||||
| giveall | giveall [uid] [数量] | player.giveall | 均可使用 | 给予指定玩家全部物品 | givea |
|
||||
| godmode | godmode [uid] | player.godmode | 仅客户端 | 保护你不受到任何伤害(依然会被击退) | |
|
||||
|
@ -72,8 +72,9 @@ dependencies {
|
||||
implementation group: 'org.quartz-scheduler', name: 'quartz', version: '2.3.2'
|
||||
implementation group: 'org.quartz-scheduler', name: 'quartz-jobs', version: '2.3.2'
|
||||
|
||||
protobuf files('proto/')
|
||||
implementation group: 'org.luaj', name: 'luaj-jse', version: '3.0.1'
|
||||
|
||||
protobuf files('proto/')
|
||||
}
|
||||
|
||||
application {
|
||||
|
@ -10,6 +10,7 @@ public final class Config {
|
||||
public String PACKETS_FOLDER = "./packets/";
|
||||
public String DUMPS_FOLDER = "./dumps/";
|
||||
public String KEY_FOLDER = "./keys/";
|
||||
public String SCRIPTS_FOLDER = "./resources/Scripts/";
|
||||
public String PLUGINS_FOLDER = "./plugins/";
|
||||
|
||||
public String RunMode = "HYBRID"; // HYBRID, DISPATCH_ONLY, GAME_ONLY
|
||||
|
@ -9,6 +9,7 @@ import java.net.InetSocketAddress;
|
||||
|
||||
import emu.grasscutter.command.CommandMap;
|
||||
import emu.grasscutter.plugin.PluginManager;
|
||||
import emu.grasscutter.scripts.ScriptLoader;
|
||||
import emu.grasscutter.utils.Utils;
|
||||
import org.reflections.Reflections;
|
||||
import org.slf4j.LoggerFactory;
|
||||
@ -67,6 +68,7 @@ public final class Grasscutter {
|
||||
|
||||
// Load all resources.
|
||||
ResourceLoader.loadAll();
|
||||
ScriptLoader.init();
|
||||
// Database
|
||||
DatabaseManager.initialize();
|
||||
|
||||
|
@ -18,79 +18,86 @@ public final class ClearCommand implements CommandHandler {
|
||||
@Override
|
||||
public void execute(Player sender, List<String> args) {
|
||||
int target;
|
||||
String cmdSwitch = "";
|
||||
if (sender == null) {
|
||||
CommandHandler.sendMessage(null, "Run this command in-game.");
|
||||
return;
|
||||
}
|
||||
String cmdSwitch = args.get(1);
|
||||
|
||||
Inventory playerInventory = sender.getInventory();
|
||||
try {
|
||||
try {
|
||||
if (args.size() == 1) {
|
||||
cmdSwitch = args.get(0);
|
||||
target = sender.getUid();
|
||||
}else {
|
||||
cmdSwitch = args.get(1);
|
||||
target = Integer.parseInt(args.get(0));
|
||||
Player targetPlayer = Grasscutter.getGameServer().getPlayerByUid(target);
|
||||
if (targetPlayer == null) {
|
||||
target = sender.getUid();
|
||||
} else {
|
||||
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()));
|
||||
sender.dropMessage("Cleared weapons for " + targetPlayer.getNickname() + " .");
|
||||
}
|
||||
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()));
|
||||
sender.dropMessage("Cleared artifacts for " + targetPlayer.getNickname() + " .");
|
||||
}
|
||||
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()));
|
||||
sender.dropMessage("Cleared artifacts for " + targetPlayer.getNickname() + " .");
|
||||
}
|
||||
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()));
|
||||
playerInventory.getItems().values().stream()
|
||||
.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()));
|
||||
playerInventory.getItems().values().stream()
|
||||
.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()));
|
||||
playerInventory.getItems().values().stream()
|
||||
.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() + " .");
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (NumberFormatException ignored) {
|
||||
// TODO: Parse from item name using GM Handbook.
|
||||
CommandHandler.sendMessage(sender, "Invalid playerId.");
|
||||
return;
|
||||
}
|
||||
Player targetPlayer = Grasscutter.getGameServer().getPlayerByUid(target);
|
||||
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()));
|
||||
sender.dropMessage("Cleared weapons for " + targetPlayer.getNickname() + " .");
|
||||
}
|
||||
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()));
|
||||
sender.dropMessage("Cleared artifacts for " + targetPlayer.getNickname() + " .");
|
||||
}
|
||||
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()));
|
||||
sender.dropMessage("Cleared artifacts for " + targetPlayer.getNickname() + " .");
|
||||
}
|
||||
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()));
|
||||
sender.dropMessage("Cleared artifacts for " + targetPlayer.getNickname() + " .");
|
||||
playerInventory.getItems().values().stream()
|
||||
.filter(item2 -> item2.getItemType() == ItemType.ITEM_MATERIAL)
|
||||
.filter(item2 -> !item2.isLocked() && !item2.isEquipped())
|
||||
.forEach(item2 -> playerInventory.removeItem(item2, item2.getCount()));
|
||||
sender.dropMessage("Cleared materials for " + targetPlayer.getNickname() + " .");
|
||||
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()));
|
||||
sender.dropMessage("Cleared weapons for " + targetPlayer.getNickname() + " .");
|
||||
playerInventory.getItems().values().stream()
|
||||
.filter(item4 -> item4.getItemType() == ItemType.ITEM_FURNITURE)
|
||||
.filter(item4 -> !item4.isLocked() && !item4.isEquipped())
|
||||
.forEach(item4 -> playerInventory.removeItem(item4, item4.getCount()));
|
||||
sender.dropMessage("Cleared furniture for " + targetPlayer.getNickname() + " .");
|
||||
playerInventory.getItems().values().stream()
|
||||
.filter(item5 -> item5.getItemType() == ItemType.ITEM_DISPLAY)
|
||||
.filter(item5 -> !item5.isLocked() && !item5.isEquipped())
|
||||
.forEach(item5 -> playerInventory.removeItem(item5, item5.getCount()));
|
||||
sender.dropMessage("Cleared displays for " + targetPlayer.getNickname() + " .");
|
||||
playerInventory.getItems().values().stream()
|
||||
.filter(item6 -> item6.getItemType() == ItemType.ITEM_VIRTUAL)
|
||||
.filter(item6 -> !item6.isLocked() && !item6.isEquipped())
|
||||
.forEach(item6 -> playerInventory.removeItem(item6, item6.getCount()));
|
||||
sender.dropMessage("Cleared virtuals for " + targetPlayer.getNickname() + " .");
|
||||
sender.dropMessage("Cleared everything for " + targetPlayer.getNickname() + " .");
|
||||
}
|
||||
}
|
||||
} catch (NumberFormatException ignored) {
|
||||
// TODO: Parse from item name using GM Handbook.
|
||||
CommandHandler.sendMessage(sender, "Invalid playerId.");
|
||||
return;
|
||||
}
|
||||
|
||||
Player targetPlayer = Grasscutter.getGameServer().getPlayerByUid(target);
|
||||
if (targetPlayer == null) {
|
||||
|
@ -83,9 +83,6 @@ public class GiveAllCommand implements CommandHandler {
|
||||
Avatar avatar = new Avatar(avatarData);
|
||||
avatar.setLevel(90);
|
||||
avatar.setPromoteLevel(6);
|
||||
for (int i = 1; i <= 6; ++i) {
|
||||
avatar.getTalentIdList().add((avatar.getAvatarId() - 10000000) * 10 + i);
|
||||
}
|
||||
// This will handle stats and talents
|
||||
avatar.recalcStats();
|
||||
player.addAvatar(avatar);
|
||||
@ -98,7 +95,7 @@ public class GiveAllCommand implements CommandHandler {
|
||||
if (isTestItem(itemdata.getId())) continue;
|
||||
|
||||
if (itemdata.isEquip()) {
|
||||
for (int i = 0; i < 10; ++i) {
|
||||
for (int i = 0; i < 5; ++i) {
|
||||
GameItem item = new GameItem(itemdata);
|
||||
if (itemdata.getItemType() == ItemType.ITEM_WEAPON) {
|
||||
item.setLevel(90);
|
||||
@ -114,7 +111,7 @@ public class GiveAllCommand implements CommandHandler {
|
||||
itemList.add(item);
|
||||
}
|
||||
}
|
||||
int packetNum = 20;
|
||||
int packetNum = 10;
|
||||
int itemLength = itemList.size();
|
||||
int number = itemLength / packetNum;
|
||||
int remainder = itemLength % packetNum;
|
||||
@ -171,15 +168,27 @@ public class GiveAllCommand implements CommandHandler {
|
||||
private static final Range[] testItemRanges = new Range[] {
|
||||
new Range(106, 139),
|
||||
new Range(1000, 1099),
|
||||
new Range(2001, 2008),
|
||||
new Range(2017, 2029),
|
||||
// new Range(108001, 108387) //food
|
||||
new Range(2001, 3022),
|
||||
new Range(23300, 23340),
|
||||
new Range(23383, 23385),
|
||||
new Range(78310, 78554),
|
||||
new Range(99310, 99554),
|
||||
new Range(100001, 100187),
|
||||
new Range(100210, 100214),
|
||||
new Range(100303, 100398),
|
||||
new Range(100414, 100425),
|
||||
new Range(100454, 103008),
|
||||
new Range(109000, 109492),
|
||||
new Range(115001, 118004),
|
||||
new Range(141001, 141072),
|
||||
new Range(220050, 221016),
|
||||
};
|
||||
private static final Integer[] testItemsIds = new Integer[] {
|
||||
210, 211, 314, 315, 317, 1005, 1007, 1105, 1107, 1201, 1202, 2800,
|
||||
100001, 100002, 100244, 100305, 100312, 100313, 101212, 11411, 11506, 11507, 11508, 12505,
|
||||
12506, 12508, 12509, 13503, 13506, 14411, 14503, 14505, 14508, 15411, 15504, 15505,
|
||||
15506, 15508, 20001, 10002, 10003, 10004, 10005, 10006, 10008 //9
|
||||
210, 211, 314, 315, 317, 1005, 1007, 1105, 1107, 1201, 1202,10366,
|
||||
101212, 11411, 11506, 11507, 11508, 12505, 12506, 12508, 12509, 13503,
|
||||
13506, 14411, 14503, 14505, 14508, 15411, 15504, 15505, 15506, 15508,
|
||||
20001, 10002, 10003, 10004, 10005, 10006, 10008,100231,100232,100431,
|
||||
101689,105001,105004, 106000,106001,108000,110000
|
||||
};
|
||||
|
||||
private static final Collection<Integer> testItemsList = Arrays.asList(testItemsIds);
|
||||
|
@ -6,20 +6,20 @@ import emu.grasscutter.command.CommandHandler;
|
||||
import emu.grasscutter.data.GameData;
|
||||
import emu.grasscutter.data.def.ItemData;
|
||||
import emu.grasscutter.game.inventory.GameItem;
|
||||
import emu.grasscutter.game.inventory.ItemType;
|
||||
import emu.grasscutter.game.player.Player;
|
||||
import emu.grasscutter.game.props.ActionReason;
|
||||
import emu.grasscutter.server.packet.send.PacketItemAddHintNotify;
|
||||
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
|
||||
@Command(label = "give", usage = "give [player] <itemId|itemName> [amount] [level]", description = "Gives an item to you or the specified player", aliases = {
|
||||
"g", "item", "giveitem" }, permission = "player.give")
|
||||
"g", "item", "giveitem"}, permission = "player.give")
|
||||
public final class GiveCommand implements CommandHandler {
|
||||
|
||||
@Override
|
||||
public void execute(Player sender, List<String> args) {
|
||||
int target, item, lvl, amount = 1;
|
||||
int target, item, lvl, amount = 1, refinement = 0;
|
||||
if (sender == null && args.size() < 2) {
|
||||
CommandHandler.sendMessage(null, "Usage: give <player> <itemId|itemName> [amount] [level]");
|
||||
return;
|
||||
@ -79,7 +79,28 @@ public final class GiveCommand implements CommandHandler {
|
||||
return;
|
||||
}
|
||||
break;
|
||||
case 4: // [player] <itemId|itemName> [amount] [level]
|
||||
case 4: // [player] <itemId|itemName> [amount] [level] | <itemId|itemName> [amount] [level] [refinement]
|
||||
try {
|
||||
target = Integer.parseInt(args.get(0));
|
||||
|
||||
if (Grasscutter.getGameServer().getPlayerByUid(target) == null && sender != null) {
|
||||
target = sender.getUid();
|
||||
item = Integer.parseInt(args.get(0));
|
||||
amount = Integer.parseInt(args.get(1));
|
||||
lvl = Integer.parseInt(args.get(2));
|
||||
refinement = Integer.parseInt(args.get(3));
|
||||
} else {
|
||||
item = Integer.parseInt(args.get(1));
|
||||
amount = Integer.parseInt(args.get(2));
|
||||
lvl = Integer.parseInt(args.get(3));
|
||||
}
|
||||
} catch (NumberFormatException ignored) {
|
||||
// TODO: Parse from item name using GM Handbook.
|
||||
CommandHandler.sendMessage(sender, "Invalid item or player ID.");
|
||||
return;
|
||||
}
|
||||
break;
|
||||
case 5: // [player] <itemId|itemName> [amount] [level] [refinement]
|
||||
try {
|
||||
target = Integer.parseInt(args.get(0));
|
||||
|
||||
@ -90,6 +111,7 @@ public final class GiveCommand implements CommandHandler {
|
||||
item = Integer.parseInt(args.get(1));
|
||||
amount = Integer.parseInt(args.get(2));
|
||||
lvl = Integer.parseInt(args.get(3));
|
||||
refinement = Integer.parseInt(args.get(4));
|
||||
}
|
||||
} catch (NumberFormatException ignored) {
|
||||
// TODO: Parse from item name using GM Handbook.
|
||||
@ -111,37 +133,58 @@ public final class GiveCommand implements CommandHandler {
|
||||
CommandHandler.sendMessage(sender, "Invalid item id.");
|
||||
return;
|
||||
}
|
||||
if (refinement != 0) {
|
||||
if (itemData.getItemType() == ItemType.ITEM_WEAPON) {
|
||||
if (refinement < 1 || refinement > 5) {
|
||||
CommandHandler.sendMessage(sender, "Refinement must be between 1 and 5.");
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
CommandHandler.sendMessage(sender, "Refinement is only applicable to weapons.");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
this.item(targetPlayer, itemData, amount, lvl);
|
||||
this.item(targetPlayer, itemData, amount, lvl, refinement);
|
||||
|
||||
if (!itemData.isEquip())
|
||||
if (!itemData.isEquip()) {
|
||||
CommandHandler.sendMessage(sender, String.format("Given %s of %s to %s.", amount, item, target));
|
||||
else
|
||||
} else if (itemData.getItemType() == ItemType.ITEM_WEAPON) {
|
||||
CommandHandler.sendMessage(sender,
|
||||
String.format("Given %s with level %s, refinement %s %s times to %s", item, lvl, refinement, amount, target));
|
||||
} else {
|
||||
CommandHandler.sendMessage(sender,
|
||||
String.format("Given %s with level %s %s times to %s", item, lvl, amount, target));
|
||||
}
|
||||
}
|
||||
|
||||
private void item(Player player, ItemData itemData, int amount, int lvl) {
|
||||
private void item(Player player, ItemData itemData, int amount, int lvl, int refinement) {
|
||||
if (itemData.isEquip()) {
|
||||
List<GameItem> items = new LinkedList<>();
|
||||
for (int i = 0; i < amount; i++) {
|
||||
GameItem item = new GameItem(itemData);
|
||||
item.setCount(amount);
|
||||
item.setLevel(lvl);
|
||||
item.setPromoteLevel(0);
|
||||
if (lvl > 20) { // 20/40
|
||||
if (lvl > 20 && lvl < 40) {
|
||||
item.setPromoteLevel(1);
|
||||
} else if (lvl > 40) { // 40/50
|
||||
} else if (lvl > 40 && lvl <= 50) {
|
||||
item.setPromoteLevel(2);
|
||||
} else if (lvl > 50) { // 50/60
|
||||
} else if (lvl > 50 && lvl <= 60) {
|
||||
item.setPromoteLevel(3);
|
||||
} else if (lvl > 60) { // 60/70
|
||||
} else if (lvl > 60 && lvl <= 70) {
|
||||
item.setPromoteLevel(4);
|
||||
} else if (lvl > 70) { // 70/80
|
||||
} else if (lvl > 70 && lvl <= 80) {
|
||||
item.setPromoteLevel(5);
|
||||
} else if (lvl > 80) { // 80/90
|
||||
} else if (lvl > 80 && lvl <= 90) {
|
||||
item.setPromoteLevel(6);
|
||||
}
|
||||
if (item.getItemType() == ItemType.ITEM_WEAPON) {
|
||||
if (refinement > 0) {
|
||||
item.setRefinement(refinement - 1);
|
||||
} else {
|
||||
item.setRefinement(0);
|
||||
}
|
||||
}
|
||||
items.add(item);
|
||||
}
|
||||
player.getInventory().addItems(items, ActionReason.SubfieldDrop);
|
||||
|
@ -61,13 +61,15 @@ public class GameData {
|
||||
private static final Int2ObjectMap<FetterCharacterCardData> fetterCharacterCardDataMap = new Int2ObjectOpenHashMap<>();
|
||||
private static final Int2ObjectMap<RewardData> rewardDataMap = new Int2ObjectOpenHashMap<>();
|
||||
private static final Int2ObjectMap<WorldLevelData> worldLevelDataMap = new Int2ObjectOpenHashMap<>();
|
||||
|
||||
private static final Int2ObjectMap<DungeonData> dungeonDataMap = new Int2ObjectOpenHashMap<>();
|
||||
private static final Int2ObjectMap<ShopGoodsData> shopGoodsDataMap = new Int2ObjectOpenHashMap<>();
|
||||
|
||||
// Cache
|
||||
private static Map<Integer, List<Integer>> fetters = new HashMap<>();
|
||||
private static Map<Integer, List<ShopGoodsData>> shopGoods = new HashMap<>();
|
||||
|
||||
public static char EJWOA = 's';
|
||||
|
||||
public static Int2ObjectMap<?> getMapByResourceDef(Class<?> resourceDefinition) {
|
||||
Int2ObjectMap<?> map = null;
|
||||
|
||||
@ -101,6 +103,11 @@ public class GameData {
|
||||
return scenePointEntries;
|
||||
}
|
||||
|
||||
// TODO optimize
|
||||
public static ScenePointEntry getScenePointEntryById(int sceneId, int pointId) {
|
||||
return getScenePointEntries().get(sceneId + "_" + pointId);
|
||||
}
|
||||
|
||||
public static Int2ObjectMap<AvatarData> getAvatarDataMap() {
|
||||
return avatarDataMap;
|
||||
}
|
||||
@ -269,7 +276,9 @@ public class GameData {
|
||||
return worldLevelDataMap;
|
||||
}
|
||||
|
||||
public static char EJWOA = 's';
|
||||
public static Int2ObjectMap<DungeonData> getDungeonDataMap() {
|
||||
return dungeonDataMap;
|
||||
}
|
||||
|
||||
public static Map<Integer, List<ShopGoodsData>> getShopGoodsDataEntries() {
|
||||
if (shopGoods.isEmpty()) {
|
||||
|
@ -164,6 +164,7 @@ public class ResourceLoader {
|
||||
|
||||
for (Map.Entry<String, JsonElement> entry : config.points.entrySet()) {
|
||||
PointData pointData = Grasscutter.getGsonFactory().fromJson(entry.getValue(), PointData.class);
|
||||
pointData.setId(Integer.parseInt(entry.getKey()));
|
||||
|
||||
ScenePointEntry sl = new ScenePointEntry(sceneId + "_" + entry.getKey(), pointData);
|
||||
scenePointList.add(sl);
|
||||
|
@ -1,43 +1,30 @@
|
||||
package emu.grasscutter.data.common;
|
||||
|
||||
public class PointData {
|
||||
private pos tranPos;
|
||||
import emu.grasscutter.utils.Position;
|
||||
|
||||
public pos getTranPos() {
|
||||
public class PointData {
|
||||
private int id;
|
||||
private String $type;
|
||||
private Position tranPos;
|
||||
private int[] dungeonIds;
|
||||
|
||||
public int getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(int id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public String getType() {
|
||||
return $type;
|
||||
}
|
||||
|
||||
public Position getTranPos() {
|
||||
return tranPos;
|
||||
}
|
||||
|
||||
public void setTranPos(pos tranPos) {
|
||||
this.tranPos = tranPos;
|
||||
}
|
||||
|
||||
public class pos {
|
||||
private float x;
|
||||
private float y;
|
||||
private float z;
|
||||
|
||||
public float getX() {
|
||||
return x;
|
||||
}
|
||||
|
||||
public void setX(float x) {
|
||||
this.x = x;
|
||||
}
|
||||
|
||||
public float getY() {
|
||||
return y;
|
||||
}
|
||||
|
||||
public void setY(float y) {
|
||||
this.y = y;
|
||||
}
|
||||
|
||||
public float getZ() {
|
||||
return z;
|
||||
}
|
||||
|
||||
public void setZ(float z) {
|
||||
this.z = z;
|
||||
}
|
||||
}
|
||||
public int[] getDungeonIds() {
|
||||
return dungeonIds;
|
||||
}
|
||||
}
|
||||
|
33
src/main/java/emu/grasscutter/data/def/DungeonData.java
Normal file
33
src/main/java/emu/grasscutter/data/def/DungeonData.java
Normal file
@ -0,0 +1,33 @@
|
||||
package emu.grasscutter.data.def;
|
||||
|
||||
import emu.grasscutter.data.GameData;
|
||||
import emu.grasscutter.data.GameResource;
|
||||
import emu.grasscutter.data.ResourceType;
|
||||
|
||||
import emu.grasscutter.game.props.SceneType;
|
||||
|
||||
@ResourceType(name = "DungeonExcelConfigData.json")
|
||||
public class DungeonData extends GameResource {
|
||||
private int Id;
|
||||
private int SceneId;
|
||||
private int ShowLevel;
|
||||
private String InvolveType; // TODO enum
|
||||
|
||||
@Override
|
||||
public int getId() {
|
||||
return this.Id;
|
||||
}
|
||||
|
||||
public int getSceneId() {
|
||||
return SceneId;
|
||||
}
|
||||
|
||||
public int getShowLevel() {
|
||||
return ShowLevel;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onLoad() {
|
||||
|
||||
}
|
||||
}
|
@ -2,12 +2,13 @@ package emu.grasscutter.data.def;
|
||||
|
||||
import emu.grasscutter.data.GameResource;
|
||||
import emu.grasscutter.data.ResourceType;
|
||||
import emu.grasscutter.game.props.EntityType;
|
||||
|
||||
@ResourceType(name = "GadgetExcelConfigData.json")
|
||||
public class GadgetData extends GameResource {
|
||||
private int Id;
|
||||
|
||||
private String Type;
|
||||
private EntityType Type;
|
||||
private String JsonName;
|
||||
private boolean IsInteractive;
|
||||
private String[] Tags;
|
||||
@ -22,7 +23,7 @@ public class GadgetData extends GameResource {
|
||||
return this.Id;
|
||||
}
|
||||
|
||||
public String getType() {
|
||||
public EntityType getType() {
|
||||
return Type;
|
||||
}
|
||||
|
||||
|
@ -9,16 +9,17 @@ import emu.grasscutter.game.props.SceneType;
|
||||
@ResourceType(name = "SceneExcelConfigData.json")
|
||||
public class SceneData extends GameResource {
|
||||
private int Id;
|
||||
private SceneType SceneType;
|
||||
private SceneType Type;
|
||||
private String ScriptData;
|
||||
|
||||
|
||||
@Override
|
||||
public int getId() {
|
||||
return this.Id;
|
||||
}
|
||||
|
||||
public SceneType getSceneType() {
|
||||
return SceneType;
|
||||
return Type;
|
||||
}
|
||||
|
||||
public String getScriptData() {
|
||||
|
@ -0,0 +1,105 @@
|
||||
package emu.grasscutter.game.dungeons;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import emu.grasscutter.data.GameData;
|
||||
import emu.grasscutter.data.def.MonsterData;
|
||||
import emu.grasscutter.game.entity.EntityMonster;
|
||||
import emu.grasscutter.game.entity.GameEntity;
|
||||
import emu.grasscutter.game.world.Scene;
|
||||
import emu.grasscutter.net.proto.VisionTypeOuterClass.VisionType;
|
||||
import emu.grasscutter.scripts.constants.EventType;
|
||||
import emu.grasscutter.scripts.data.SceneGroup;
|
||||
import emu.grasscutter.scripts.data.SceneMonster;
|
||||
import emu.grasscutter.server.packet.send.PacketChallengeDataNotify;
|
||||
import emu.grasscutter.server.packet.send.PacketDungeonChallengeBeginNotify;
|
||||
import emu.grasscutter.server.packet.send.PacketDungeonChallengeFinishNotify;
|
||||
import emu.grasscutter.server.packet.send.PacketSceneEntityAppearNotify;
|
||||
|
||||
public class DungeonChallenge {
|
||||
private final Scene scene;
|
||||
private final SceneGroup group;
|
||||
|
||||
private int challengeIndex;
|
||||
private int challengeId;
|
||||
private boolean success;
|
||||
private boolean progress;
|
||||
|
||||
private int score;
|
||||
private int objective = 0;
|
||||
|
||||
public DungeonChallenge(Scene scene, SceneGroup group) {
|
||||
this.scene = scene;
|
||||
this.group = group;
|
||||
|
||||
objective += group.monsters.size();
|
||||
}
|
||||
|
||||
public Scene getScene() {
|
||||
return scene;
|
||||
}
|
||||
|
||||
public SceneGroup getGroup() {
|
||||
return group;
|
||||
}
|
||||
|
||||
public int getChallengeIndex() {
|
||||
return challengeIndex;
|
||||
}
|
||||
|
||||
public void setChallengeIndex(int challengeIndex) {
|
||||
this.challengeIndex = challengeIndex;
|
||||
}
|
||||
|
||||
public int getChallengeId() {
|
||||
return challengeId;
|
||||
}
|
||||
|
||||
public void setChallengeId(int challengeId) {
|
||||
this.challengeId = challengeId;
|
||||
}
|
||||
|
||||
public boolean isSuccess() {
|
||||
return success;
|
||||
}
|
||||
|
||||
public void setSuccess(boolean isSuccess) {
|
||||
this.success = isSuccess;
|
||||
}
|
||||
|
||||
public boolean inProgress() {
|
||||
return progress;
|
||||
}
|
||||
|
||||
public int getScore() {
|
||||
return score;
|
||||
}
|
||||
|
||||
public void start() {
|
||||
this.progress = true;
|
||||
getScene().broadcastPacket(new PacketDungeonChallengeBeginNotify(this));
|
||||
}
|
||||
|
||||
public void finish() {
|
||||
this.progress = false;
|
||||
getScene().broadcastPacket(new PacketDungeonChallengeFinishNotify(this));
|
||||
|
||||
if (this.isSuccess()) {
|
||||
this.getScene().getScriptManager().callEvent(EventType.EVENT_CHALLENGE_SUCCESS, null);
|
||||
} else {
|
||||
this.getScene().getScriptManager().callEvent(EventType.EVENT_CHALLENGE_FAIL, null);
|
||||
}
|
||||
}
|
||||
|
||||
public void onMonsterDie(EntityMonster entity) {
|
||||
score = getScore() + 1;
|
||||
|
||||
getScene().broadcastPacket(new PacketChallengeDataNotify(this, 1, getScore()));
|
||||
|
||||
if (getScore() >= objective) {
|
||||
this.setSuccess(true);
|
||||
finish();
|
||||
}
|
||||
}
|
||||
}
|
@ -1,6 +1,18 @@
|
||||
package emu.grasscutter.game.dungeons;
|
||||
|
||||
import emu.grasscutter.GameConstants;
|
||||
import emu.grasscutter.Grasscutter;
|
||||
import emu.grasscutter.data.GameData;
|
||||
import emu.grasscutter.data.custom.ScenePointEntry;
|
||||
import emu.grasscutter.data.def.DungeonData;
|
||||
import emu.grasscutter.game.player.Player;
|
||||
import emu.grasscutter.game.props.SceneType;
|
||||
import emu.grasscutter.net.packet.BasePacket;
|
||||
import emu.grasscutter.net.packet.PacketOpcodes;
|
||||
import emu.grasscutter.server.game.GameServer;
|
||||
import emu.grasscutter.server.packet.send.PacketDungeonEntryInfoRsp;
|
||||
import emu.grasscutter.server.packet.send.PacketPlayerEnterDungeonRsp;
|
||||
import emu.grasscutter.utils.Position;
|
||||
|
||||
public class DungeonManager {
|
||||
private final GameServer server;
|
||||
@ -12,4 +24,59 @@ public class DungeonManager {
|
||||
public GameServer getServer() {
|
||||
return server;
|
||||
}
|
||||
|
||||
public void getEntryInfo(Player player, int pointId) {
|
||||
ScenePointEntry entry = GameData.getScenePointEntryById(player.getScene().getId(), pointId);
|
||||
|
||||
if (entry == null || entry.getPointData().getDungeonIds() == null) {
|
||||
// Error
|
||||
player.sendPacket(new PacketDungeonEntryInfoRsp());
|
||||
return;
|
||||
}
|
||||
|
||||
player.sendPacket(new PacketDungeonEntryInfoRsp(player, entry.getPointData()));
|
||||
}
|
||||
|
||||
public void enterDungeon(Player player, int pointId, int dungeonId) {
|
||||
DungeonData data = GameData.getDungeonDataMap().get(dungeonId);
|
||||
|
||||
if (data == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
Grasscutter.getLogger().info(player.getNickname() + " is trying to enter dungeon " + dungeonId);
|
||||
|
||||
int sceneId = data.getSceneId();
|
||||
player.getScene().setPrevScene(sceneId);
|
||||
|
||||
player.getWorld().transferPlayerToScene(player, sceneId, data);
|
||||
|
||||
player.getScene().setPrevScenePoint(pointId);
|
||||
player.sendPacket(new PacketPlayerEnterDungeonRsp(pointId, dungeonId));
|
||||
}
|
||||
|
||||
public void exitDungeon(Player player) {
|
||||
if (player.getScene().getSceneType() != SceneType.SCENE_DUNGEON) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Get previous scene
|
||||
int prevScene = player.getScene().getPrevScene() > 0 ? player.getScene().getPrevScene() : 3;
|
||||
|
||||
// Get previous position
|
||||
DungeonData dungeonData = player.getScene().getDungeonData();
|
||||
Position prevPos = new Position(GameConstants.START_POSITION);
|
||||
|
||||
if (dungeonData != null) {
|
||||
ScenePointEntry entry = GameData.getScenePointEntryById(prevScene, player.getScene().getPrevScenePoint());
|
||||
|
||||
if (entry != null) {
|
||||
prevPos.set(entry.getPointData().getTranPos());
|
||||
}
|
||||
}
|
||||
|
||||
// Transfer player back to world
|
||||
player.getWorld().transferPlayerToScene(player, prevScene, prevPos);
|
||||
player.sendPacket(new BasePacket(PacketOpcodes.PlayerQuitDungeonRsp));
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,18 @@
|
||||
package emu.grasscutter.game.entity;
|
||||
|
||||
import emu.grasscutter.game.world.Scene;
|
||||
import emu.grasscutter.game.world.World;
|
||||
|
||||
public abstract class EntityBaseGadget extends GameEntity {
|
||||
|
||||
public EntityBaseGadget(Scene scene) {
|
||||
super(scene);
|
||||
}
|
||||
|
||||
public abstract int getGadgetId();
|
||||
|
||||
@Override
|
||||
public void onDeath(int killerId) {
|
||||
|
||||
}
|
||||
}
|
@ -23,7 +23,7 @@ import emu.grasscutter.utils.Position;
|
||||
import emu.grasscutter.utils.ProtoHelper;
|
||||
import it.unimi.dsi.fastutil.ints.Int2FloatOpenHashMap;
|
||||
|
||||
public class EntityClientGadget extends EntityGadget {
|
||||
public class EntityClientGadget extends EntityBaseGadget {
|
||||
private final Player owner;
|
||||
|
||||
private final Position pos;
|
||||
|
@ -1,18 +1,157 @@
|
||||
package emu.grasscutter.game.entity;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
import emu.grasscutter.data.GameData;
|
||||
import emu.grasscutter.data.def.GadgetData;
|
||||
import emu.grasscutter.game.props.EntityIdType;
|
||||
import emu.grasscutter.game.props.EntityType;
|
||||
import emu.grasscutter.game.props.PlayerProperty;
|
||||
import emu.grasscutter.game.world.Scene;
|
||||
import emu.grasscutter.game.world.World;
|
||||
import emu.grasscutter.net.proto.ClientGadgetInfoOuterClass;
|
||||
import emu.grasscutter.net.proto.AbilitySyncStateInfoOuterClass.AbilitySyncStateInfo;
|
||||
import emu.grasscutter.net.proto.AnimatorParameterValueInfoPairOuterClass.AnimatorParameterValueInfoPair;
|
||||
import emu.grasscutter.net.proto.EntityAuthorityInfoOuterClass.EntityAuthorityInfo;
|
||||
import emu.grasscutter.net.proto.EntityClientDataOuterClass.EntityClientData;
|
||||
import emu.grasscutter.net.proto.EntityRendererChangedInfoOuterClass.EntityRendererChangedInfo;
|
||||
import emu.grasscutter.net.proto.MotionInfoOuterClass.MotionInfo;
|
||||
import emu.grasscutter.net.proto.PropPairOuterClass.PropPair;
|
||||
import emu.grasscutter.net.proto.ProtEntityTypeOuterClass.ProtEntityType;
|
||||
import emu.grasscutter.net.proto.SceneEntityAiInfoOuterClass.SceneEntityAiInfo;
|
||||
import emu.grasscutter.net.proto.SceneEntityInfoOuterClass.SceneEntityInfo;
|
||||
import emu.grasscutter.net.proto.SceneGadgetInfoOuterClass.SceneGadgetInfo;
|
||||
import emu.grasscutter.net.proto.VectorOuterClass.Vector;
|
||||
import emu.grasscutter.net.proto.WorktopInfoOuterClass.WorktopInfo;
|
||||
import emu.grasscutter.utils.Position;
|
||||
import emu.grasscutter.utils.ProtoHelper;
|
||||
import it.unimi.dsi.fastutil.ints.Int2FloatOpenHashMap;
|
||||
import it.unimi.dsi.fastutil.ints.IntArrayList;
|
||||
import it.unimi.dsi.fastutil.ints.IntList;
|
||||
import it.unimi.dsi.fastutil.ints.IntOpenHashSet;
|
||||
import it.unimi.dsi.fastutil.ints.IntSet;
|
||||
|
||||
public abstract class EntityGadget extends GameEntity {
|
||||
public class EntityGadget extends EntityBaseGadget {
|
||||
private final GadgetData data;
|
||||
private final Position pos;
|
||||
private final Position rot;
|
||||
private int gadgetId;
|
||||
|
||||
public EntityGadget(Scene scene) {
|
||||
private int state;
|
||||
private IntSet worktopOptions;
|
||||
|
||||
public EntityGadget(Scene scene, int gadgetId, Position pos) {
|
||||
super(scene);
|
||||
this.data = GameData.getGadgetDataMap().get(gadgetId);
|
||||
this.id = getScene().getWorld().getNextEntityId(EntityIdType.GADGET);
|
||||
this.gadgetId = gadgetId;
|
||||
this.pos = pos.clone();
|
||||
this.rot = new Position();
|
||||
}
|
||||
|
||||
public abstract int getGadgetId();
|
||||
public GadgetData getGadgetData() {
|
||||
return data;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Position getPosition() {
|
||||
// TODO Auto-generated method stub
|
||||
return this.pos;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Position getRotation() {
|
||||
// TODO Auto-generated method stub
|
||||
return this.rot;
|
||||
}
|
||||
|
||||
public int getGadgetId() {
|
||||
return gadgetId;
|
||||
}
|
||||
|
||||
public void setGadgetId(int gadgetId) {
|
||||
this.gadgetId = gadgetId;
|
||||
}
|
||||
|
||||
public int getState() {
|
||||
return state;
|
||||
}
|
||||
|
||||
public void setState(int state) {
|
||||
this.state = state;
|
||||
}
|
||||
|
||||
public IntSet getWorktopOptions() {
|
||||
return worktopOptions;
|
||||
}
|
||||
|
||||
public void addWorktopOptions(int[] options) {
|
||||
if (this.worktopOptions == null) {
|
||||
this.worktopOptions = new IntOpenHashSet();
|
||||
}
|
||||
Arrays.stream(options).forEach(this.worktopOptions::add);
|
||||
}
|
||||
|
||||
public void removeWorktopOption(int option) {
|
||||
if (this.worktopOptions == null) {
|
||||
return;
|
||||
}
|
||||
this.worktopOptions.remove(option);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Int2FloatOpenHashMap getFightProperties() {
|
||||
// TODO Auto-generated method stub
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDeath(int killerId) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public SceneEntityInfo toProto() {
|
||||
EntityAuthorityInfo authority = EntityAuthorityInfo.newBuilder()
|
||||
.setAbilityInfo(AbilitySyncStateInfo.newBuilder())
|
||||
.setRendererChangedInfo(EntityRendererChangedInfo.newBuilder())
|
||||
.setAiInfo(SceneEntityAiInfo.newBuilder().setIsAiOpen(true).setBornPos(Vector.newBuilder()))
|
||||
.setBornPos(Vector.newBuilder())
|
||||
.build();
|
||||
|
||||
SceneEntityInfo.Builder entityInfo = SceneEntityInfo.newBuilder()
|
||||
.setEntityId(getId())
|
||||
.setEntityType(ProtEntityType.PROT_ENTITY_GADGET)
|
||||
.setMotionInfo(MotionInfo.newBuilder().setPos(getPosition().toProto()).setRot(getRotation().toProto()).setSpeed(Vector.newBuilder()))
|
||||
.addAnimatorParaList(AnimatorParameterValueInfoPair.newBuilder())
|
||||
.setEntityClientData(EntityClientData.newBuilder())
|
||||
.setEntityAuthorityInfo(authority)
|
||||
.setLifeState(1);
|
||||
|
||||
PropPair pair = PropPair.newBuilder()
|
||||
.setType(PlayerProperty.PROP_LEVEL.getId())
|
||||
.setPropValue(ProtoHelper.newPropValue(PlayerProperty.PROP_LEVEL, 1))
|
||||
.build();
|
||||
entityInfo.addPropList(pair);
|
||||
|
||||
SceneGadgetInfo.Builder gadgetInfo = SceneGadgetInfo.newBuilder()
|
||||
.setGadgetId(this.getGadgetId())
|
||||
.setGroupId(this.getGroupId())
|
||||
.setConfigId(this.getConfigId())
|
||||
.setGadgetState(this.getState())
|
||||
.setIsEnableInteract(true)
|
||||
.setAuthorityPeerId(this.getScene().getWorld().getHostPeerId());
|
||||
|
||||
if (this.getGadgetData().getType() == EntityType.Worktop && this.getWorktopOptions() != null) {
|
||||
WorktopInfo worktop = WorktopInfo.newBuilder()
|
||||
.addAllOptionList(this.getWorktopOptions())
|
||||
.build();
|
||||
gadgetInfo.setWorktop(worktop);
|
||||
}
|
||||
|
||||
entityInfo.setGadget(gadgetInfo);
|
||||
|
||||
return entityInfo.build();
|
||||
}
|
||||
}
|
||||
|
@ -23,7 +23,7 @@ import emu.grasscutter.utils.Position;
|
||||
import emu.grasscutter.utils.ProtoHelper;
|
||||
import it.unimi.dsi.fastutil.ints.Int2FloatOpenHashMap;
|
||||
|
||||
public class EntityItem extends EntityGadget {
|
||||
public class EntityItem extends EntityBaseGadget {
|
||||
private final Position pos;
|
||||
private final Position rot;
|
||||
|
||||
|
@ -4,6 +4,7 @@ import emu.grasscutter.data.GameData;
|
||||
import emu.grasscutter.data.common.PropGrowCurve;
|
||||
import emu.grasscutter.data.def.MonsterCurveData;
|
||||
import emu.grasscutter.data.def.MonsterData;
|
||||
import emu.grasscutter.game.dungeons.DungeonChallenge;
|
||||
import emu.grasscutter.game.props.EntityIdType;
|
||||
import emu.grasscutter.game.props.FightProperty;
|
||||
import emu.grasscutter.game.props.PlayerProperty;
|
||||
@ -22,6 +23,7 @@ import emu.grasscutter.net.proto.SceneEntityAiInfoOuterClass.SceneEntityAiInfo;
|
||||
import emu.grasscutter.net.proto.SceneEntityInfoOuterClass.SceneEntityInfo;
|
||||
import emu.grasscutter.net.proto.SceneMonsterInfoOuterClass.SceneMonsterInfo;
|
||||
import emu.grasscutter.net.proto.SceneWeaponInfoOuterClass.SceneWeaponInfo;
|
||||
import emu.grasscutter.scripts.constants.EventType;
|
||||
import emu.grasscutter.utils.Position;
|
||||
import emu.grasscutter.utils.ProtoHelper;
|
||||
import it.unimi.dsi.fastutil.ints.Int2FloatMap;
|
||||
@ -36,9 +38,6 @@ public class EntityMonster extends GameEntity {
|
||||
private final Position bornPos;
|
||||
private final int level;
|
||||
private int weaponEntityId;
|
||||
|
||||
private int groupId;
|
||||
private int configId;
|
||||
private int poseId;
|
||||
|
||||
public EntityMonster(Scene scene, MonsterData monsterData, Position pos, int level) {
|
||||
@ -104,22 +103,6 @@ public class EntityMonster extends GameEntity {
|
||||
return this.getFightProperty(FightProperty.FIGHT_PROP_CUR_HP) > 0f;
|
||||
}
|
||||
|
||||
public int getGroupId() {
|
||||
return groupId;
|
||||
}
|
||||
|
||||
public void setGroupId(int groupId) {
|
||||
this.groupId = groupId;
|
||||
}
|
||||
|
||||
public int getConfigId() {
|
||||
return configId;
|
||||
}
|
||||
|
||||
public void setConfigId(int configId) {
|
||||
this.configId = configId;
|
||||
}
|
||||
|
||||
public int getPoseId() {
|
||||
return poseId;
|
||||
}
|
||||
@ -133,6 +116,12 @@ public class EntityMonster extends GameEntity {
|
||||
if (this.getSpawnEntry() != null) {
|
||||
this.getScene().getDeadSpawnedEntities().add(getSpawnEntry());
|
||||
}
|
||||
if (getScene().getScriptManager().isInit() && this.getGroupId() > 0) {
|
||||
getScene().getScriptManager().callEvent(EventType.EVENT_ANY_MONSTER_DIE, null);
|
||||
}
|
||||
if (getScene().getChallenge() != null && getScene().getChallenge().getGroup().id == this.getGroupId()) {
|
||||
getScene().getChallenge().onMonsterDie(this);
|
||||
}
|
||||
}
|
||||
|
||||
public void recalcStats() {
|
||||
|
@ -25,7 +25,7 @@ import emu.grasscutter.utils.ProtoHelper;
|
||||
import it.unimi.dsi.fastutil.ints.Int2FloatMap;
|
||||
import it.unimi.dsi.fastutil.ints.Int2FloatOpenHashMap;
|
||||
|
||||
public class EntityVehicle extends EntityGadget {
|
||||
public class EntityVehicle extends EntityBaseGadget {
|
||||
private final Player owner;
|
||||
private final Int2FloatOpenHashMap fightProp;
|
||||
|
||||
|
@ -17,6 +17,10 @@ public abstract class GameEntity {
|
||||
private final Scene scene;
|
||||
private SpawnDataEntry spawnEntry;
|
||||
|
||||
private int blockId;
|
||||
private int configId;
|
||||
private int groupId;
|
||||
|
||||
private MotionState moveState;
|
||||
private int lastMoveSceneTimeMs;
|
||||
private int lastMoveReliableSeq;
|
||||
@ -96,6 +100,30 @@ public abstract class GameEntity {
|
||||
return getFightProperties().getOrDefault(prop.getId(), 0f);
|
||||
}
|
||||
|
||||
public int getBlockId() {
|
||||
return blockId;
|
||||
}
|
||||
|
||||
public void setBlockId(int blockId) {
|
||||
this.blockId = blockId;
|
||||
}
|
||||
|
||||
public int getConfigId() {
|
||||
return configId;
|
||||
}
|
||||
|
||||
public void setConfigId(int configId) {
|
||||
this.configId = configId;
|
||||
}
|
||||
|
||||
public int getGroupId() {
|
||||
return groupId;
|
||||
}
|
||||
|
||||
public void setGroupId(int groupId) {
|
||||
this.groupId = groupId;
|
||||
}
|
||||
|
||||
protected MotionInfo getMotionInfo() {
|
||||
MotionInfo proto = MotionInfo.newBuilder()
|
||||
.setPos(getPosition().toProto())
|
||||
|
@ -15,7 +15,7 @@ import emu.grasscutter.Grasscutter;
|
||||
import emu.grasscutter.data.def.AvatarSkillDepotData;
|
||||
import emu.grasscutter.game.avatar.Avatar;
|
||||
import emu.grasscutter.game.entity.EntityAvatar;
|
||||
import emu.grasscutter.game.entity.EntityGadget;
|
||||
import emu.grasscutter.game.entity.EntityBaseGadget;
|
||||
import emu.grasscutter.game.props.ElementType;
|
||||
import emu.grasscutter.game.props.EnterReason;
|
||||
import emu.grasscutter.game.props.FightProperty;
|
||||
@ -54,7 +54,7 @@ public class TeamManager {
|
||||
@Transient private TeamInfo mpTeam;
|
||||
@Transient private int entityId;
|
||||
@Transient private final List<EntityAvatar> avatars;
|
||||
@Transient private final Set<EntityGadget> gadgets;
|
||||
@Transient private final Set<EntityBaseGadget> gadgets;
|
||||
@Transient private final IntSet teamResonances;
|
||||
@Transient private final IntSet teamResonancesConfig;
|
||||
|
||||
@ -141,7 +141,7 @@ public class TeamManager {
|
||||
this.entityId = entityId;
|
||||
}
|
||||
|
||||
public Set<EntityGadget> getGadgets() {
|
||||
public Set<EntityBaseGadget> getGadgets() {
|
||||
return gadgets;
|
||||
}
|
||||
|
||||
|
93
src/main/java/emu/grasscutter/game/props/EntityType.java
Normal file
93
src/main/java/emu/grasscutter/game/props/EntityType.java
Normal file
@ -0,0 +1,93 @@
|
||||
package emu.grasscutter.game.props;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
|
||||
import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap;
|
||||
|
||||
public enum EntityType {
|
||||
None (0),
|
||||
Avatar (1),
|
||||
Monster (2),
|
||||
Bullet (3),
|
||||
AttackPhyisicalUnit (4),
|
||||
AOE (5),
|
||||
Camera (6),
|
||||
EnviroArea (7),
|
||||
Equip (8),
|
||||
MonsterEquip (9),
|
||||
Grass (10),
|
||||
Level (11),
|
||||
NPC (12),
|
||||
TransPointFirst (13),
|
||||
TransPointFirstGadget (14),
|
||||
TransPointSecond (15),
|
||||
TransPointSecondGadget (16),
|
||||
DropItem (17),
|
||||
Field (18),
|
||||
Gadget (19),
|
||||
Water (20),
|
||||
GatherPoint (21),
|
||||
GatherObject (22),
|
||||
AirflowField (23),
|
||||
SpeedupField (24),
|
||||
Gear (25),
|
||||
Chest (26),
|
||||
EnergyBall (27),
|
||||
ElemCrystal (28),
|
||||
Timeline (29),
|
||||
Worktop (30),
|
||||
Team (31),
|
||||
Platform (32),
|
||||
AmberWind (33),
|
||||
EnvAnimal (34),
|
||||
SealGadget (35),
|
||||
Tree (36),
|
||||
Bush (37),
|
||||
QuestGadget (38),
|
||||
Lightning (39),
|
||||
RewardPoint (40),
|
||||
RewardStatue (41),
|
||||
MPLevel (42),
|
||||
WindSeed (43),
|
||||
MpPlayRewardPoint (44),
|
||||
ViewPoint (45),
|
||||
RemoteAvatar (46),
|
||||
GeneralRewardPoint (47),
|
||||
PlayTeam (48),
|
||||
OfferingGadget (49),
|
||||
EyePoint (50),
|
||||
MiracleRing (51),
|
||||
Foundation (52),
|
||||
WidgetGadget (53),
|
||||
PlaceHolder (99);
|
||||
|
||||
private final int value;
|
||||
private static final Int2ObjectMap<EntityType> map = new Int2ObjectOpenHashMap<>();
|
||||
private static final Map<String, EntityType> stringMap = new HashMap<>();
|
||||
|
||||
static {
|
||||
Stream.of(values()).forEach(e -> {
|
||||
map.put(e.getValue(), e);
|
||||
stringMap.put(e.name(), e);
|
||||
});
|
||||
}
|
||||
|
||||
private EntityType(int value) {
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
public int getValue() {
|
||||
return value;
|
||||
}
|
||||
|
||||
public static EntityType getTypeByValue(int value) {
|
||||
return map.getOrDefault(value, None);
|
||||
}
|
||||
|
||||
public static EntityType getTypeByName(String name) {
|
||||
return stringMap.getOrDefault(name, None);
|
||||
}
|
||||
}
|
@ -3,9 +3,11 @@ package emu.grasscutter.game.world;
|
||||
import emu.grasscutter.Grasscutter;
|
||||
import emu.grasscutter.data.GameData;
|
||||
import emu.grasscutter.data.GameDepot;
|
||||
import emu.grasscutter.data.def.DungeonData;
|
||||
import emu.grasscutter.data.def.MonsterData;
|
||||
import emu.grasscutter.data.def.SceneData;
|
||||
import emu.grasscutter.data.def.WorldLevelData;
|
||||
import emu.grasscutter.game.dungeons.DungeonChallenge;
|
||||
import emu.grasscutter.game.entity.*;
|
||||
import emu.grasscutter.game.player.Player;
|
||||
import emu.grasscutter.game.player.TeamInfo;
|
||||
@ -17,6 +19,13 @@ import emu.grasscutter.game.world.SpawnDataEntry.SpawnGroupEntry;
|
||||
import emu.grasscutter.net.packet.BasePacket;
|
||||
import emu.grasscutter.net.proto.AttackResultOuterClass.AttackResult;
|
||||
import emu.grasscutter.net.proto.VisionTypeOuterClass.VisionType;
|
||||
import emu.grasscutter.scripts.SceneScriptManager;
|
||||
import emu.grasscutter.scripts.constants.EventType;
|
||||
import emu.grasscutter.scripts.data.SceneBlock;
|
||||
import emu.grasscutter.scripts.data.SceneGadget;
|
||||
import emu.grasscutter.scripts.data.SceneGroup;
|
||||
import emu.grasscutter.scripts.data.ScriptArgs;
|
||||
import emu.grasscutter.server.packet.send.PacketDungeonChallengeFinishNotify;
|
||||
import emu.grasscutter.server.packet.send.PacketEntityFightPropUpdateNotify;
|
||||
import emu.grasscutter.server.packet.send.PacketLifeStateChangeNotify;
|
||||
import emu.grasscutter.server.packet.send.PacketSceneEntityAppearNotify;
|
||||
@ -36,12 +45,19 @@ public class Scene {
|
||||
|
||||
private final Set<SpawnDataEntry> spawnedEntities;
|
||||
private final Set<SpawnDataEntry> deadSpawnedEntities;
|
||||
private final Set<SceneBlock> loadedBlocks;
|
||||
private boolean dontDestroyWhenEmpty;
|
||||
|
||||
private int time;
|
||||
private ClimateType climate;
|
||||
private int weather;
|
||||
|
||||
private SceneScriptManager scriptManager;
|
||||
private DungeonChallenge challenge;
|
||||
private DungeonData dungeonData;
|
||||
private int prevScene; // Id of the previous scene
|
||||
private int prevScenePoint;
|
||||
|
||||
public Scene(World world, SceneData sceneData) {
|
||||
this.world = world;
|
||||
this.sceneData = sceneData;
|
||||
@ -50,9 +66,12 @@ public class Scene {
|
||||
|
||||
this.time = 8 * 60;
|
||||
this.climate = ClimateType.CLIMATE_SUNNY;
|
||||
this.prevScene = 3;
|
||||
|
||||
this.spawnedEntities = new HashSet<>();
|
||||
this.deadSpawnedEntities = new HashSet<>();
|
||||
this.loadedBlocks = new HashSet<>();
|
||||
this.scriptManager = new SceneScriptManager(this);
|
||||
}
|
||||
|
||||
public int getId() {
|
||||
@ -111,6 +130,22 @@ public class Scene {
|
||||
this.weather = weather;
|
||||
}
|
||||
|
||||
public int getPrevScene() {
|
||||
return prevScene;
|
||||
}
|
||||
|
||||
public void setPrevScene(int prevScene) {
|
||||
this.prevScene = prevScene;
|
||||
}
|
||||
|
||||
public int getPrevScenePoint() {
|
||||
return prevScenePoint;
|
||||
}
|
||||
|
||||
public void setPrevScenePoint(int prevPoint) {
|
||||
this.prevScenePoint = prevPoint;
|
||||
}
|
||||
|
||||
public boolean dontDestroyWhenEmpty() {
|
||||
return dontDestroyWhenEmpty;
|
||||
}
|
||||
@ -119,6 +154,10 @@ public class Scene {
|
||||
this.dontDestroyWhenEmpty = dontDestroyWhenEmpty;
|
||||
}
|
||||
|
||||
public Set<SceneBlock> getLoadedBlocks() {
|
||||
return loadedBlocks;
|
||||
}
|
||||
|
||||
public Set<SpawnDataEntry> getSpawnedEntities() {
|
||||
return spawnedEntities;
|
||||
}
|
||||
@ -127,6 +166,29 @@ public class Scene {
|
||||
return deadSpawnedEntities;
|
||||
}
|
||||
|
||||
public SceneScriptManager getScriptManager() {
|
||||
return scriptManager;
|
||||
}
|
||||
|
||||
public DungeonData getDungeonData() {
|
||||
return dungeonData;
|
||||
}
|
||||
|
||||
public void setDungeonData(DungeonData dungeonData) {
|
||||
if (this.dungeonData != null || this.getSceneType() != SceneType.SCENE_DUNGEON || dungeonData.getSceneId() != this.getId()) {
|
||||
return;
|
||||
}
|
||||
this.dungeonData = dungeonData;
|
||||
}
|
||||
|
||||
public DungeonChallenge getChallenge() {
|
||||
return challenge;
|
||||
}
|
||||
|
||||
public void setChallenge(DungeonChallenge challenge) {
|
||||
this.challenge = challenge;
|
||||
}
|
||||
|
||||
public boolean isInScene(GameEntity entity) {
|
||||
return this.entities.containsKey(entity.getId());
|
||||
}
|
||||
@ -151,6 +213,11 @@ public class Scene {
|
||||
}
|
||||
|
||||
public synchronized void removePlayer(Player player) {
|
||||
// Remove from challenge if leaving
|
||||
if (this.getChallenge() != null && this.getChallenge().inProgress()) {
|
||||
player.sendPacket(new PacketDungeonChallengeFinishNotify(this.getChallenge()));
|
||||
}
|
||||
|
||||
// Remove player from scene
|
||||
getPlayers().remove(player);
|
||||
player.setScene(null);
|
||||
@ -159,12 +226,12 @@ public class Scene {
|
||||
this.removePlayerAvatars(player);
|
||||
|
||||
// Remove player gadgets
|
||||
for (EntityGadget gadget : player.getTeamManager().getGadgets()) {
|
||||
for (EntityBaseGadget gadget : player.getTeamManager().getGadgets()) {
|
||||
this.removeEntity(gadget);
|
||||
}
|
||||
|
||||
// Deregister scene if not in use
|
||||
if (this.getEntities().size() <= 0 && !this.dontDestroyWhenEmpty()) {
|
||||
if (this.getPlayerCount() <= 0 && !this.dontDestroyWhenEmpty()) {
|
||||
this.getWorld().deregisterScene(this);
|
||||
}
|
||||
}
|
||||
@ -279,6 +346,11 @@ public class Scene {
|
||||
}
|
||||
}
|
||||
|
||||
// Sanity check
|
||||
if (target.getFightProperties() == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Lose hp
|
||||
target.addFightProperty(FightProperty.FIGHT_PROP_CUR_HP, -result.getDamage());
|
||||
|
||||
@ -314,7 +386,15 @@ public class Scene {
|
||||
}
|
||||
|
||||
public void onTick() {
|
||||
this.checkSpawns();
|
||||
if (this.getScriptManager().isInit()) {
|
||||
this.checkBlocks();
|
||||
} else {
|
||||
// TEMPORARY
|
||||
this.checkSpawns();
|
||||
}
|
||||
|
||||
// Triggers
|
||||
this.getScriptManager().onTick();
|
||||
}
|
||||
|
||||
// TODO - Test
|
||||
@ -387,6 +467,68 @@ public class Scene {
|
||||
}
|
||||
}
|
||||
|
||||
public void checkBlocks() {
|
||||
Set<SceneBlock> visible = new HashSet<>();
|
||||
|
||||
for (Player player : this.getPlayers()) {
|
||||
for (SceneBlock block : getScriptManager().getBlocks()) {
|
||||
if (!block.contains(player.getPos())) {
|
||||
continue;
|
||||
}
|
||||
|
||||
visible.add(block);
|
||||
}
|
||||
}
|
||||
|
||||
Iterator<SceneBlock> it = this.getLoadedBlocks().iterator();
|
||||
while (it.hasNext()) {
|
||||
SceneBlock block = it.next();
|
||||
|
||||
if (!visible.contains(block)) {
|
||||
it.remove();
|
||||
|
||||
onUnloadBlock(block);
|
||||
}
|
||||
}
|
||||
|
||||
for (SceneBlock block : visible) {
|
||||
if (!this.getLoadedBlocks().contains(block)) {
|
||||
this.onLoadBlock(block);
|
||||
this.getLoadedBlocks().add(block);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// TODO optimize
|
||||
public void onLoadBlock(SceneBlock block) {
|
||||
for (SceneGroup group : block.groups) {
|
||||
// We load the script files for the groups here
|
||||
if (!group.isLoaded()) {
|
||||
this.getScriptManager().loadGroupFromScript(group);
|
||||
}
|
||||
|
||||
group.triggers.forEach(getScriptManager()::registerTrigger);
|
||||
}
|
||||
|
||||
// Spawn gadgets AFTER triggers are added
|
||||
for (SceneGroup group : block.groups) {
|
||||
this.getScriptManager().spawnGadgetsInGroup(group);
|
||||
}
|
||||
}
|
||||
|
||||
public void onUnloadBlock(SceneBlock block) {
|
||||
List<GameEntity> toRemove = this.getEntities().values().stream().filter(e -> e.getBlockId() == block.id).toList();
|
||||
|
||||
if (toRemove.size() > 0) {
|
||||
toRemove.stream().forEach(this::removeEntityDirectly);
|
||||
this.broadcastPacket(new PacketSceneEntityDisappearNotify(toRemove, VisionType.VISION_REMOVE));
|
||||
}
|
||||
|
||||
for (SceneGroup group : block.groups) {
|
||||
group.triggers.forEach(getScriptManager()::deregisterTrigger);
|
||||
}
|
||||
}
|
||||
|
||||
// Gadgets
|
||||
|
||||
public void onPlayerCreateGadget(EntityClientGadget gadget) {
|
||||
|
@ -17,14 +17,16 @@ import emu.grasscutter.game.props.EntityIdType;
|
||||
import emu.grasscutter.game.props.FightProperty;
|
||||
import emu.grasscutter.game.props.LifeState;
|
||||
import emu.grasscutter.data.GameData;
|
||||
import emu.grasscutter.data.def.DungeonData;
|
||||
import emu.grasscutter.data.def.SceneData;
|
||||
import emu.grasscutter.game.entity.EntityAvatar;
|
||||
import emu.grasscutter.game.entity.EntityClientGadget;
|
||||
import emu.grasscutter.game.entity.EntityGadget;
|
||||
import emu.grasscutter.game.entity.EntityBaseGadget;
|
||||
import emu.grasscutter.net.packet.BasePacket;
|
||||
import emu.grasscutter.net.proto.AttackResultOuterClass.AttackResult;
|
||||
import emu.grasscutter.net.proto.EnterTypeOuterClass.EnterType;
|
||||
import emu.grasscutter.net.proto.VisionTypeOuterClass.VisionType;
|
||||
import emu.grasscutter.scripts.data.SceneConfig;
|
||||
import emu.grasscutter.server.packet.send.PacketDelTeamEntityNotify;
|
||||
import emu.grasscutter.server.packet.send.PacketEntityFightPropUpdateNotify;
|
||||
import emu.grasscutter.server.packet.send.PacketLifeStateChangeNotify;
|
||||
@ -212,6 +214,14 @@ public class World implements Iterable<Player> {
|
||||
}
|
||||
|
||||
public boolean transferPlayerToScene(Player player, int sceneId, Position pos) {
|
||||
return transferPlayerToScene(player, sceneId, null, pos);
|
||||
}
|
||||
|
||||
public boolean transferPlayerToScene(Player player, int sceneId, DungeonData data) {
|
||||
return transferPlayerToScene(player, sceneId, data, null);
|
||||
}
|
||||
|
||||
public boolean transferPlayerToScene(Player player, int sceneId, DungeonData dungeonData, Position pos) {
|
||||
if (GameData.getSceneDataMap().get(sceneId) == null) {
|
||||
return false;
|
||||
}
|
||||
@ -230,19 +240,45 @@ public class World implements Iterable<Player> {
|
||||
}
|
||||
|
||||
Scene newScene = this.getSceneById(sceneId);
|
||||
newScene.setDungeonData(dungeonData);
|
||||
newScene.addPlayer(player);
|
||||
|
||||
// Dungeon
|
||||
SceneConfig config = newScene.getScriptManager().getConfig();
|
||||
if (pos == null && config != null) {
|
||||
if (config.born_pos != null) {
|
||||
pos = newScene.getScriptManager().getConfig().born_pos;
|
||||
}
|
||||
if (config.born_rot != null) {
|
||||
player.getRotation().set(config.born_rot);
|
||||
}
|
||||
}
|
||||
|
||||
// Set player position
|
||||
if (pos == null) {
|
||||
pos = player.getPos();
|
||||
}
|
||||
|
||||
player.getPos().set(pos);
|
||||
|
||||
if (oldScene != null) {
|
||||
newScene.setPrevScene(oldScene.getId());
|
||||
oldScene.setDontDestroyWhenEmpty(false);
|
||||
}
|
||||
|
||||
// Teleport packet
|
||||
if (oldScene == newScene) {
|
||||
player.sendPacket(new PacketPlayerEnterSceneNotify(player, EnterType.ENTER_GOTO, EnterReason.TransPoint, sceneId, pos));
|
||||
} else {
|
||||
player.sendPacket(new PacketPlayerEnterSceneNotify(player, EnterType.ENTER_JUMP, EnterReason.TransPoint, sceneId, pos));
|
||||
// Get enter types
|
||||
EnterType enterType = EnterType.ENTER_JUMP;
|
||||
EnterReason enterReason = EnterReason.TransPoint;
|
||||
|
||||
if (dungeonData != null) {
|
||||
enterType = EnterType.ENTER_DUNGEON;
|
||||
enterReason = EnterReason.DungeonEnter;
|
||||
} else if (oldScene == newScene) {
|
||||
enterType = EnterType.ENTER_GOTO;
|
||||
}
|
||||
|
||||
// Teleport packet
|
||||
player.sendPacket(new PacketPlayerEnterSceneNotify(player, enterType, enterReason, sceneId, pos));
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -355,6 +355,8 @@ public class PacketOpcodes {
|
||||
public static final int EvtAvatarSitDownNotify = 392;
|
||||
public static final int EvtAvatarStandUpNotify = 358;
|
||||
public static final int EvtAvatarUpdateFocusNotify = 365;
|
||||
public static final int EvtAvatarLockChairReq = 354;
|
||||
public static final int EvtAvatarLockChairRsp = 335;
|
||||
public static final int EvtBeingHitNotify = 360;
|
||||
public static final int EvtBeingHitsCombineNotify = 381;
|
||||
public static final int EvtBulletDeactiveNotify = 388;
|
||||
|
@ -66,7 +66,7 @@ public final class PluginManager {
|
||||
Enumeration<JarEntry> entries = jarFile.entries();
|
||||
while(entries.hasMoreElements()) {
|
||||
JarEntry entry = entries.nextElement();
|
||||
if(entry.isDirectory() || !entry.getName().endsWith(".class")) continue;
|
||||
if(entry.isDirectory() || !entry.getName().endsWith(".class") || entry.getName().contains("module-info")) continue;
|
||||
String className = entry.getName().replace(".class", "").replace("/", ".");
|
||||
Class<?> clazz = loader.loadClass(className);
|
||||
}
|
||||
|
345
src/main/java/emu/grasscutter/scripts/SceneScriptManager.java
Normal file
345
src/main/java/emu/grasscutter/scripts/SceneScriptManager.java
Normal file
@ -0,0 +1,345 @@
|
||||
package emu.grasscutter.scripts;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import javax.script.Bindings;
|
||||
import javax.script.CompiledScript;
|
||||
import javax.script.ScriptException;
|
||||
|
||||
import org.luaj.vm2.LuaTable;
|
||||
import org.luaj.vm2.LuaValue;
|
||||
import org.luaj.vm2.lib.jse.CoerceJavaToLua;
|
||||
|
||||
import emu.grasscutter.Grasscutter;
|
||||
import emu.grasscutter.data.GameData;
|
||||
import emu.grasscutter.data.def.MonsterData;
|
||||
import emu.grasscutter.data.def.WorldLevelData;
|
||||
import emu.grasscutter.game.entity.EntityGadget;
|
||||
import emu.grasscutter.game.entity.EntityMonster;
|
||||
import emu.grasscutter.game.entity.GameEntity;
|
||||
import emu.grasscutter.game.world.Scene;
|
||||
import emu.grasscutter.scripts.constants.EventType;
|
||||
import emu.grasscutter.scripts.constants.ScriptGadgetState;
|
||||
import emu.grasscutter.scripts.constants.ScriptRegionShape;
|
||||
import emu.grasscutter.scripts.data.SceneBlock;
|
||||
import emu.grasscutter.scripts.data.SceneConfig;
|
||||
import emu.grasscutter.scripts.data.SceneGadget;
|
||||
import emu.grasscutter.scripts.data.SceneGroup;
|
||||
import emu.grasscutter.scripts.data.SceneInitConfig;
|
||||
import emu.grasscutter.scripts.data.SceneMonster;
|
||||
import emu.grasscutter.scripts.data.SceneSuite;
|
||||
import emu.grasscutter.scripts.data.SceneTrigger;
|
||||
import emu.grasscutter.scripts.data.SceneVar;
|
||||
import emu.grasscutter.scripts.data.ScriptArgs;
|
||||
import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
|
||||
import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap;
|
||||
|
||||
public class SceneScriptManager {
|
||||
private final Scene scene;
|
||||
private final ScriptLib scriptLib;
|
||||
private final LuaValue scriptLibLua;
|
||||
private final Map<String, Integer> variables;
|
||||
|
||||
private Bindings bindings;
|
||||
private SceneConfig config;
|
||||
private List<SceneBlock> blocks;
|
||||
private Int2ObjectOpenHashMap<Set<SceneTrigger>> triggers;
|
||||
private boolean isInit;
|
||||
|
||||
public SceneScriptManager(Scene scene) {
|
||||
this.scene = scene;
|
||||
this.scriptLib = new ScriptLib(this);
|
||||
this.scriptLibLua = CoerceJavaToLua.coerce(this.scriptLib);
|
||||
this.triggers = new Int2ObjectOpenHashMap<>();
|
||||
this.variables = new HashMap<>();
|
||||
|
||||
// TEMPORARY
|
||||
if (this.getScene().getId() < 10) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Create
|
||||
this.init();
|
||||
}
|
||||
|
||||
public Scene getScene() {
|
||||
return scene;
|
||||
}
|
||||
|
||||
public ScriptLib getScriptLib() {
|
||||
return scriptLib;
|
||||
}
|
||||
|
||||
public LuaValue getScriptLibLua() {
|
||||
return scriptLibLua;
|
||||
}
|
||||
|
||||
public Bindings getBindings() {
|
||||
return bindings;
|
||||
}
|
||||
|
||||
public SceneConfig getConfig() {
|
||||
return config;
|
||||
}
|
||||
|
||||
public List<SceneBlock> getBlocks() {
|
||||
return blocks;
|
||||
}
|
||||
|
||||
public Map<String, Integer> getVariables() {
|
||||
return variables;
|
||||
}
|
||||
|
||||
public Set<SceneTrigger> getTriggersByEvent(int eventId) {
|
||||
return triggers.computeIfAbsent(eventId, e -> new HashSet<>());
|
||||
}
|
||||
|
||||
public void registerTrigger(SceneTrigger trigger) {
|
||||
getTriggersByEvent(trigger.event).add(trigger);
|
||||
}
|
||||
|
||||
public void deregisterTrigger(SceneTrigger trigger) {
|
||||
getTriggersByEvent(trigger.event).remove(trigger);
|
||||
}
|
||||
|
||||
// TODO optimize
|
||||
public SceneGroup getGroupById(int groupId) {
|
||||
for (SceneBlock block : this.getScene().getLoadedBlocks()) {
|
||||
for (SceneGroup group : block.groups) {
|
||||
if (group.id == groupId) {
|
||||
return group;
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private void init() {
|
||||
// Get compiled script if cached
|
||||
CompiledScript cs = ScriptLoader.getScriptByPath(
|
||||
Grasscutter.getConfig().SCRIPTS_FOLDER + "Scene/" + getScene().getId() + "/scene" + getScene().getId() + "." + ScriptLoader.getScriptType());
|
||||
|
||||
if (cs == null) {
|
||||
Grasscutter.getLogger().warn("No script found for scene " + getScene().getId());
|
||||
return;
|
||||
}
|
||||
|
||||
// Create bindings
|
||||
bindings = ScriptLoader.getEngine().createBindings();
|
||||
|
||||
// Set variables
|
||||
bindings.put("EventType", new EventType()); // TODO - make static class to avoid instantiating a new class every scene
|
||||
bindings.put("GadgetState", new ScriptGadgetState());
|
||||
bindings.put("RegionShape", new ScriptRegionShape());
|
||||
bindings.put("ScriptLib", getScriptLib());
|
||||
|
||||
// Eval script
|
||||
try {
|
||||
cs.eval(getBindings());
|
||||
|
||||
this.config = ScriptLoader.getSerializer().toObject(SceneConfig.class, bindings.get("scene_config"));
|
||||
|
||||
// TODO optimize later
|
||||
// Create blocks
|
||||
List<Integer> blockIds = ScriptLoader.getSerializer().toList(Integer.class, bindings.get("blocks"));
|
||||
List<SceneBlock> blocks = ScriptLoader.getSerializer().toList(SceneBlock.class, bindings.get("block_rects"));
|
||||
|
||||
for (int i = 0; i < blocks.size(); i++) {
|
||||
SceneBlock block = blocks.get(0);
|
||||
block.id = blockIds.get(i);
|
||||
|
||||
loadBlockFromScript(block);
|
||||
}
|
||||
|
||||
this.blocks = blocks;
|
||||
} catch (ScriptException e) {
|
||||
Grasscutter.getLogger().error("Error running script", e);
|
||||
return;
|
||||
}
|
||||
|
||||
// TEMP
|
||||
this.isInit = true;
|
||||
}
|
||||
|
||||
public boolean isInit() {
|
||||
return isInit;
|
||||
}
|
||||
|
||||
private void loadBlockFromScript(SceneBlock block) {
|
||||
CompiledScript cs = ScriptLoader.getScriptByPath(
|
||||
Grasscutter.getConfig().SCRIPTS_FOLDER + "Scene/" + getScene().getId() + "/scene" + getScene().getId() + "_block" + block.id + "." + ScriptLoader.getScriptType());
|
||||
|
||||
if (cs == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Eval script
|
||||
try {
|
||||
cs.eval(getBindings());
|
||||
|
||||
// Set groups
|
||||
block.groups = ScriptLoader.getSerializer().toList(SceneGroup.class, bindings.get("groups"));
|
||||
block.groups.forEach(g -> g.block_id = block.id);
|
||||
} catch (ScriptException e) {
|
||||
Grasscutter.getLogger().error("Error loading block " + block.id + " in scene " + getScene().getId(), e);
|
||||
}
|
||||
}
|
||||
|
||||
public void loadGroupFromScript(SceneGroup group) {
|
||||
// Set flag here so if there is no script, we dont call this function over and over again.
|
||||
group.setLoaded(true);
|
||||
|
||||
CompiledScript cs = ScriptLoader.getScriptByPath(
|
||||
Grasscutter.getConfig().SCRIPTS_FOLDER + "Scene/" + getScene().getId() + "/scene" + getScene().getId() + "_group" + group.id + "." + ScriptLoader.getScriptType());
|
||||
|
||||
if (cs == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Eval script
|
||||
try {
|
||||
cs.eval(getBindings());
|
||||
|
||||
// Set
|
||||
group.monsters = ScriptLoader.getSerializer().toList(SceneMonster.class, bindings.get("monsters"));
|
||||
group.gadgets = ScriptLoader.getSerializer().toList(SceneGadget.class, bindings.get("gadgets"));
|
||||
group.triggers = ScriptLoader.getSerializer().toList(SceneTrigger.class, bindings.get("triggers"));
|
||||
group.suites = ScriptLoader.getSerializer().toList(SceneSuite.class, bindings.get("suites"));
|
||||
group.init_config = ScriptLoader.getSerializer().toObject(SceneInitConfig.class, bindings.get("init_config"));
|
||||
|
||||
// Add variables to suite
|
||||
List<SceneVar> variables = ScriptLoader.getSerializer().toList(SceneVar.class, bindings.get("variables"));
|
||||
variables.forEach(var -> this.getVariables().put(var.name, var.value));
|
||||
|
||||
// Add monsters to suite TODO optimize
|
||||
HashMap<Integer, SceneMonster> map = (HashMap<Integer, SceneMonster>) group.monsters.stream().collect(Collectors.toMap(m -> m.config_id, m -> m));
|
||||
|
||||
for (SceneSuite suite : group.suites) {
|
||||
suite.sceneMonsters = new ArrayList<>(suite.monsters.size());
|
||||
for (int id : suite.monsters) {
|
||||
SceneMonster monster = map.get(id);
|
||||
if (monster != null) {
|
||||
suite.sceneMonsters.add(monster);
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (ScriptException e) {
|
||||
Grasscutter.getLogger().error("Error loading group " + group.id + " in scene " + getScene().getId(), e);
|
||||
}
|
||||
}
|
||||
|
||||
public void onTick() {
|
||||
checkTriggers();
|
||||
}
|
||||
|
||||
public void checkTriggers() {
|
||||
|
||||
}
|
||||
|
||||
public void spawnGadgetsInGroup(SceneGroup group) {
|
||||
for (SceneGadget g : group.gadgets) {
|
||||
EntityGadget entity = new EntityGadget(getScene(), g.gadget_id, g.pos);
|
||||
|
||||
if (entity.getGadgetData() == null) continue;
|
||||
|
||||
entity.setBlockId(group.block_id);
|
||||
entity.setConfigId(g.config_id);
|
||||
entity.setGroupId(group.id);
|
||||
entity.getRotation().set(g.rot);
|
||||
entity.setState(g.state);
|
||||
|
||||
getScene().addEntity(entity);
|
||||
this.callEvent(EventType.EVENT_GADGET_CREATE, new ScriptArgs(entity.getConfigId()));
|
||||
}
|
||||
}
|
||||
|
||||
public void spawnMonstersInGroup(SceneGroup group, int suiteIndex) {
|
||||
spawnMonstersInGroup(group, group.getSuiteByIndex(suiteIndex));
|
||||
}
|
||||
|
||||
public void spawnMonstersInGroup(SceneGroup group) {
|
||||
spawnMonstersInGroup(group, null);
|
||||
}
|
||||
|
||||
public void spawnMonstersInGroup(SceneGroup group, SceneSuite suite) {
|
||||
List<SceneMonster> monsters = group.monsters;
|
||||
|
||||
if (suite != null) {
|
||||
monsters = suite.sceneMonsters;
|
||||
}
|
||||
|
||||
List<GameEntity> toAdd = new ArrayList<>();
|
||||
|
||||
for (SceneMonster monster : monsters) {
|
||||
MonsterData data = GameData.getMonsterDataMap().get(monster.monster_id);
|
||||
|
||||
if (data == null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Calculate level
|
||||
int level = monster.level;
|
||||
|
||||
if (getScene().getDungeonData() != null) {
|
||||
level = getScene().getDungeonData().getShowLevel();
|
||||
} else if (getScene().getWorld().getWorldLevel() > 0) {
|
||||
WorldLevelData worldLevelData = GameData.getWorldLevelDataMap().get(getScene().getWorld().getWorldLevel());
|
||||
|
||||
if (worldLevelData != null) {
|
||||
level = worldLevelData.getMonsterLevel();
|
||||
}
|
||||
}
|
||||
|
||||
// Spawn mob
|
||||
EntityMonster entity = new EntityMonster(getScene(), data, monster.pos, level);
|
||||
entity.getRotation().set(monster.rot);
|
||||
entity.setGroupId(group.id);
|
||||
entity.setConfigId(monster.config_id);
|
||||
|
||||
toAdd.add(entity);
|
||||
}
|
||||
|
||||
if (toAdd.size() > 0) {
|
||||
getScene().addEntities(toAdd);
|
||||
|
||||
for (GameEntity entity : toAdd) {
|
||||
callEvent(EventType.EVENT_ANY_MONSTER_LIVE, new ScriptArgs(entity.getConfigId()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Events
|
||||
|
||||
public void callEvent(int eventType, ScriptArgs params) {
|
||||
for (SceneTrigger trigger : this.getTriggersByEvent(eventType)) {
|
||||
LuaValue condition = null;
|
||||
|
||||
if (trigger.condition != null && !trigger.condition.isEmpty()) {
|
||||
condition = (LuaValue) this.getBindings().get(trigger.condition);
|
||||
}
|
||||
|
||||
LuaValue ret = LuaValue.TRUE;
|
||||
|
||||
if (condition != null) {
|
||||
LuaValue args = LuaValue.NIL;
|
||||
|
||||
if (params != null) {
|
||||
args = CoerceJavaToLua.coerce(params);
|
||||
}
|
||||
|
||||
ret = condition.call(this.getScriptLibLua(), args);
|
||||
}
|
||||
|
||||
if (ret.checkboolean() == true) {
|
||||
LuaValue action = (LuaValue) this.getBindings().get(trigger.action);
|
||||
action.call(this.getScriptLibLua(), LuaValue.NIL);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
190
src/main/java/emu/grasscutter/scripts/ScriptLib.java
Normal file
190
src/main/java/emu/grasscutter/scripts/ScriptLib.java
Normal file
@ -0,0 +1,190 @@
|
||||
package emu.grasscutter.scripts;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
|
||||
import org.luaj.vm2.LuaTable;
|
||||
import org.luaj.vm2.LuaValue;
|
||||
|
||||
import emu.grasscutter.Grasscutter;
|
||||
import emu.grasscutter.data.GameData;
|
||||
import emu.grasscutter.data.def.MonsterData;
|
||||
import emu.grasscutter.game.dungeons.DungeonChallenge;
|
||||
import emu.grasscutter.game.entity.EntityGadget;
|
||||
import emu.grasscutter.game.entity.EntityMonster;
|
||||
import emu.grasscutter.game.entity.GameEntity;
|
||||
import emu.grasscutter.scripts.constants.EventType;
|
||||
import emu.grasscutter.scripts.data.SceneGroup;
|
||||
import emu.grasscutter.scripts.data.SceneMonster;
|
||||
import emu.grasscutter.scripts.data.ScriptArgs;
|
||||
import emu.grasscutter.server.packet.send.PacketGadgetStateNotify;
|
||||
import emu.grasscutter.server.packet.send.PacketWorktopOptionNotify;
|
||||
|
||||
public class ScriptLib {
|
||||
private final SceneScriptManager sceneScriptManager;
|
||||
|
||||
public ScriptLib(SceneScriptManager sceneScriptManager) {
|
||||
this.sceneScriptManager = sceneScriptManager;
|
||||
}
|
||||
|
||||
public SceneScriptManager getSceneScriptManager() {
|
||||
return sceneScriptManager;
|
||||
}
|
||||
|
||||
public int SetGadgetStateByConfigId(int configId, int gadgetState) {
|
||||
Optional<GameEntity> entity = getSceneScriptManager().getScene().getEntities().values().stream()
|
||||
.filter(e -> e.getConfigId() == configId).findFirst();
|
||||
|
||||
if (entity.isEmpty()) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (!(entity.get() instanceof EntityGadget)) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
EntityGadget gadget = (EntityGadget) entity.get();
|
||||
gadget.setState(gadgetState);
|
||||
|
||||
getSceneScriptManager().getScene().broadcastPacket(new PacketGadgetStateNotify(gadget, gadgetState));
|
||||
return 0;
|
||||
}
|
||||
|
||||
public int SetGroupGadgetStateByConfigId(int groupId, int configId, int gadgetState) {
|
||||
List<GameEntity> list = getSceneScriptManager().getScene().getEntities().values().stream()
|
||||
.filter(e -> e.getGroupId() == groupId).toList();
|
||||
|
||||
for (GameEntity entity : list) {
|
||||
if (!(entity instanceof EntityGadget)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
EntityGadget gadget = (EntityGadget) entity;
|
||||
gadget.setState(gadgetState);
|
||||
|
||||
getSceneScriptManager().getScene().broadcastPacket(new PacketGadgetStateNotify(gadget, gadgetState));
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
public int SetWorktopOptionsByGroupId(int groupId, int configId, int[] options) {
|
||||
Optional<GameEntity> entity = getSceneScriptManager().getScene().getEntities().values().stream()
|
||||
.filter(e -> e.getConfigId() == configId && e.getGroupId() == groupId).findFirst();
|
||||
|
||||
if (entity.isEmpty()) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (!(entity.get() instanceof EntityGadget)) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
EntityGadget gadget = (EntityGadget) entity.get();
|
||||
gadget.addWorktopOptions(options);
|
||||
|
||||
getSceneScriptManager().getScene().broadcastPacket(new PacketWorktopOptionNotify(gadget));
|
||||
return 0;
|
||||
}
|
||||
|
||||
public int DelWorktopOptionByGroupId(int groupId, int configId, int option) {
|
||||
Optional<GameEntity> entity = getSceneScriptManager().getScene().getEntities().values().stream()
|
||||
.filter(e -> e.getConfigId() == configId && e.getGroupId() == groupId).findFirst();
|
||||
|
||||
if (entity.isEmpty()) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (!(entity.get() instanceof EntityGadget)) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
EntityGadget gadget = (EntityGadget) entity.get();
|
||||
gadget.removeWorktopOption(option);
|
||||
|
||||
getSceneScriptManager().getScene().broadcastPacket(new PacketWorktopOptionNotify(gadget));
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Some fields are guessed
|
||||
public int AutoMonsterTide(int challengeIndex, int groupId, int[] config_ids, int param4, int param5, int param6) {
|
||||
SceneGroup group = getSceneScriptManager().getGroupById(groupId);
|
||||
|
||||
if (group == null || group.monsters == null) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
// TODO just spawn all from group for now
|
||||
this.getSceneScriptManager().spawnMonstersInGroup(group);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
public int AddExtraGroupSuite(int groupId, int suite) {
|
||||
SceneGroup group = getSceneScriptManager().getGroupById(groupId);
|
||||
|
||||
if (group == null || group.monsters == null) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
// TODO just spawn all from group for now
|
||||
this.getSceneScriptManager().spawnMonstersInGroup(group, suite);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// param3 (probably time limit for timed dungeons)
|
||||
public int ActiveChallenge(int challengeId, int challengeIndex, int param3, int groupId, int param4, int param5) {
|
||||
SceneGroup group = getSceneScriptManager().getGroupById(groupId);
|
||||
|
||||
if (group == null || group.monsters == null) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
DungeonChallenge challenge = new DungeonChallenge(getSceneScriptManager().getScene(), group);
|
||||
challenge.setChallengeId(challengeId);
|
||||
challenge.setChallengeIndex(challengeIndex);
|
||||
|
||||
getSceneScriptManager().getScene().setChallenge(challenge);
|
||||
|
||||
challenge.start();
|
||||
return 0;
|
||||
}
|
||||
|
||||
public int GetGroupMonsterCountByGroupId(int groupId) {
|
||||
return (int) getSceneScriptManager().getScene().getEntities().values().stream()
|
||||
.filter(e -> e instanceof EntityMonster && e.getGroupId() == groupId)
|
||||
.count();
|
||||
}
|
||||
|
||||
public int GetGroupVariableValue(String var) {
|
||||
return getSceneScriptManager().getVariables().getOrDefault(var, 0);
|
||||
}
|
||||
|
||||
public LuaValue ChangeGroupVariableValue(String var, int value) {
|
||||
getSceneScriptManager().getVariables().put(var, value);
|
||||
return LuaValue.ZERO;
|
||||
}
|
||||
|
||||
public int RefreshGroup(LuaTable table) {
|
||||
// Kill and Respawn?
|
||||
int groupId = table.get("group_id").toint();
|
||||
int suite = table.get("suite").toint();
|
||||
|
||||
SceneGroup group = getSceneScriptManager().getGroupById(groupId);
|
||||
|
||||
if (group == null || group.monsters == null) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
// TODO just spawn all from group for now
|
||||
this.getSceneScriptManager().spawnMonstersInGroup(group, suite);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
public void PrintContextLog(String msg) {
|
||||
Grasscutter.getLogger().info("[LUA] " + msg);
|
||||
}
|
||||
}
|
74
src/main/java/emu/grasscutter/scripts/ScriptLoader.java
Normal file
74
src/main/java/emu/grasscutter/scripts/ScriptLoader.java
Normal file
@ -0,0 +1,74 @@
|
||||
package emu.grasscutter.scripts;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.FileReader;
|
||||
import java.io.IOException;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import javax.script.Compilable;
|
||||
import javax.script.CompiledScript;
|
||||
import javax.script.ScriptEngine;
|
||||
import javax.script.ScriptEngineFactory;
|
||||
import javax.script.ScriptEngineManager;
|
||||
|
||||
import emu.grasscutter.Grasscutter;
|
||||
import emu.grasscutter.scripts.serializer.LuaSerializer;
|
||||
import emu.grasscutter.scripts.serializer.Serializer;
|
||||
|
||||
public class ScriptLoader {
|
||||
private static ScriptEngineManager sm;
|
||||
private static ScriptEngine engine;
|
||||
private static ScriptEngineFactory factory;
|
||||
private static String fileType;
|
||||
private static Serializer serializer;
|
||||
|
||||
private static Map<String, CompiledScript> scripts = new HashMap<>();
|
||||
|
||||
public synchronized static void init() throws Exception {
|
||||
if (sm != null) {
|
||||
throw new Exception("Script loader already initialized");
|
||||
}
|
||||
|
||||
sm = new ScriptEngineManager();
|
||||
engine = sm.getEngineByName("luaj");
|
||||
factory = getEngine().getFactory();
|
||||
fileType = "lua";
|
||||
serializer = new LuaSerializer();
|
||||
}
|
||||
|
||||
public static ScriptEngine getEngine() {
|
||||
return engine;
|
||||
}
|
||||
|
||||
public static String getScriptType() {
|
||||
return fileType;
|
||||
}
|
||||
|
||||
public static Serializer getSerializer() {
|
||||
return serializer;
|
||||
}
|
||||
|
||||
public static CompiledScript getScriptByPath(String path) {
|
||||
CompiledScript sc = scripts.get(path);
|
||||
|
||||
Grasscutter.getLogger().info("Loaded " + path);
|
||||
|
||||
if (sc == null) {
|
||||
File file = new File(path);
|
||||
|
||||
if (!file.exists()) return null;
|
||||
|
||||
try (FileReader fr = new FileReader(file)) {
|
||||
sc = ((Compilable) getEngine()).compile(fr);
|
||||
scripts.put(path, sc);
|
||||
} catch (Exception e) {
|
||||
//e.printStackTrace();
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
return sc;
|
||||
}
|
||||
}
|
@ -0,0 +1,82 @@
|
||||
package emu.grasscutter.scripts.constants;
|
||||
|
||||
public class EventType {
|
||||
public static final int EVENT_NONE = 0;
|
||||
public static final int EVENT_ANY_MONSTER_DIE = 1;
|
||||
public static final int EVENT_ANY_GADGET_DIE = 2;
|
||||
public static final int EVENT_VARIABLE_CHANGE = 3;
|
||||
public static final int EVENT_ENTER_REGION = 4;
|
||||
public static final int EVENT_LEAVE_REGION = 5;
|
||||
public static final int EVENT_GADGET_CREATE = 6;
|
||||
public static final int EVENT_GADGET_STATE_CHANGE = 7;
|
||||
public static final int EVENT_DUNGEON_SETTLE = 8;
|
||||
public static final int EVENT_SELECT_OPTION = 9;
|
||||
public static final int EVENT_CLIENT_EXECUTE = 10;
|
||||
public static final int EVENT_ANY_MONSTER_LIVE = 11;
|
||||
public static final int EVENT_SPECIFIC_MONSTER_HP_CHANGE = 12;
|
||||
public static final int EVENT_CITY_LEVELUP_UNLOCK_DUNGEON_ENTRY = 13;
|
||||
public static final int EVENT_DUNGEON_BROADCAST_ONTIMER = 14;
|
||||
public static final int EVENT_TIMER_EVENT = 15;
|
||||
public static final int EVENT_CHALLENGE_SUCCESS = 16;
|
||||
public static final int EVENT_CHALLENGE_FAIL = 17;
|
||||
public static final int EVENT_SEAL_BATTLE_BEGIN = 18;
|
||||
public static final int EVENT_SEAL_BATTLE_END = 19;
|
||||
public static final int EVENT_GATHER = 20;
|
||||
public static final int EVENT_QUEST_FINISH = 21;
|
||||
public static final int EVENT_MONSTER_BATTLE = 22;
|
||||
public static final int EVENT_CITY_LEVELUP = 23;
|
||||
public static final int EVENT_CUTSCENE_END = 24;
|
||||
public static final int EVENT_AVATAR_NEAR_PLATFORM = 25;
|
||||
public static final int EVENT_PLATFORM_REACH_POINT = 26;
|
||||
public static final int EVENT_UNLOCK_TRANS_POINT = 27;
|
||||
public static final int EVENT_QUEST_START = 28;
|
||||
public static final int EVENT_GROUP_LOAD = 29;
|
||||
public static final int EVENT_GROUP_WILL_UNLOAD = 30;
|
||||
public static final int EVENT_GROUP_WILL_REFRESH = 31;
|
||||
public static final int EVENT_GROUP_REFRESH = 32;
|
||||
public static final int EVENT_DUNGEON_REWARD_GET = 33;
|
||||
public static final int EVENT_SPECIFIC_GADGET_HP_CHANGE = 34;
|
||||
public static final int EVENT_MONSTER_TIDE_OVER = 35;
|
||||
public static final int EVENT_MONSTER_TIDE_CREATE = 36;
|
||||
public static final int EVENT_MONSTER_TIDE_DIE = 37;
|
||||
public static final int EVENT_SEALAMP_PHASE_CHANGE = 38;
|
||||
public static final int EVENT_BLOSSOM_PROGRESS_FINISH = 39;
|
||||
public static final int EVENT_BLOSSOM_CHEST_DIE = 40;
|
||||
public static final int EVENT_GADGET_PLAY_START = 41;
|
||||
public static final int EVENT_GADGET_PLAY_START_CD = 42;
|
||||
public static final int EVENT_GADGET_PLAY_STOP = 43;
|
||||
public static final int EVENT_GADGET_LUA_NOTIFY = 44;
|
||||
public static final int EVENT_MP_PLAY_PREPARE = 45;
|
||||
public static final int EVENT_MP_PLAY_BATTLE = 46;
|
||||
public static final int EVENT_MP_PLAY_PREPARE_INTERRUPT = 47;
|
||||
public static final int EVENT_SELECT_DIFFICULTY = 48;
|
||||
public static final int EVENT_SCENE_MP_PLAY_BATTLE_STATE = 49;
|
||||
public static final int EVENT_SCENE_MP_PLAY_BATTLE_STAGE_CHANGE = 50;
|
||||
public static final int EVENT_SCENE_MP_PLAY_BATTLE_RESULT = 51;
|
||||
public static final int EVENT_SEAL_BATTLE_PROGRESS_DECREASE = 52;
|
||||
public static final int EVENT_GENERAL_REWARD_DIE = 53;
|
||||
public static final int EVENT_SCENE_MP_PLAY_BATTLE_INTERRUPT = 54;
|
||||
public static final int EVENT_MONSTER_DIE_BEFORE_LEAVE_SCENE = 55;
|
||||
public static final int EVENT_SCENE_MP_PLAY_OPEN = 56;
|
||||
public static final int EVENT_OFFERING_LEVELUP = 57;
|
||||
public static final int EVENT_DUNGEON_REVIVE = 58;
|
||||
public static final int EVENT_SCENE_MP_PLAY_ALL_AVATAR_DIE = 59;
|
||||
public static final int EVENT_DUNGEON_ALL_AVATAR_DIE = 60;
|
||||
public static final int EVENT_GENERAL_REWARD_TAKEN = 61;
|
||||
public static final int EVENT_PLATFORM_REACH_ARRAYPOINT = 62;
|
||||
public static final int EVENT_SCENE_MULTISTAGE_PLAY_STAGE_END = 63;
|
||||
public static final int EVENT_SCENE_MULTISTAGE_PLAY_END_STAGE_REQ = 64;
|
||||
public static final int EVENT_MECHANICUS_PICKED_CARD = 65;
|
||||
public static final int EVENT_POOL_MONSTER_TIDE_OVER = 66;
|
||||
public static final int EVENT_POOL_MONSTER_TIDE_CREATE = 67;
|
||||
public static final int EVENT_POOL_MONSTER_TIDE_DIE = 68;
|
||||
public static final int EVENT_DUNGEON_AVATAR_SLIP_DIE = 69;
|
||||
public static final int EVENT_GALLERY_START = 70;
|
||||
public static final int EVENT_GALLERY_STOP = 71;
|
||||
public static final int EVENT_TIME_AXIS_PASS = 72;
|
||||
public static final int EVENT_FLEUR_FAIR_DUNGEON_ALL_PLAYER_ENTER = 73;
|
||||
public static final int EVENT_GADGETTALK_DONE = 74;
|
||||
public static final int EVENT_SET_GAME_TIME = 75;
|
||||
public static final int EVENT_HIDE_AND_SEEK_PLAYER_QUIT = 76;
|
||||
public static final int EVENT_AVATAR_DIE = 77;
|
||||
}
|
@ -0,0 +1,24 @@
|
||||
package emu.grasscutter.scripts.constants;
|
||||
|
||||
public class ScriptGadgetState {
|
||||
public static final int Default = 0;
|
||||
public static final int GatherDrop = 1;
|
||||
public static final int ChestLocked = 101;
|
||||
public static final int ChestOpened = 102;
|
||||
public static final int ChestTrap = 103;
|
||||
public static final int ChestBramble = 104;
|
||||
public static final int ChestFrozen = 105;
|
||||
public static final int ChestRock = 106;
|
||||
public static final int GearStart = 201;
|
||||
public static final int GearStop = 202;
|
||||
public static final int GearAction1 = 203;
|
||||
public static final int GearAction2 = 204;
|
||||
public static final int CrystalResonate1 = 301;
|
||||
public static final int CrystalResonate2 = 302;
|
||||
public static final int CrystalExplode = 303;
|
||||
public static final int CrystalDrain = 304;
|
||||
public static final int StatueActive = 401;
|
||||
public static final int Action01 = 901;
|
||||
public static final int Action02 = 902;
|
||||
public static final int Action03 = 903;
|
||||
}
|
@ -0,0 +1,7 @@
|
||||
package emu.grasscutter.scripts.constants;
|
||||
|
||||
public class ScriptRegionShape {
|
||||
public static final int NONE = 0;
|
||||
public static final int SPHERE = 1;
|
||||
public static final int CUBIC = 2;
|
||||
}
|
17
src/main/java/emu/grasscutter/scripts/data/SceneBlock.java
Normal file
17
src/main/java/emu/grasscutter/scripts/data/SceneBlock.java
Normal file
@ -0,0 +1,17 @@
|
||||
package emu.grasscutter.scripts.data;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import emu.grasscutter.utils.Position;
|
||||
|
||||
public class SceneBlock {
|
||||
public int id;
|
||||
public Position max;
|
||||
public Position min;
|
||||
public List<SceneGroup> groups;
|
||||
|
||||
public boolean contains(Position pos) {
|
||||
return pos.getX() <= max.getX() && pos.getX() >= min.getX() &&
|
||||
pos.getZ() <= max.getZ() && pos.getZ() >= min.getZ();
|
||||
}
|
||||
}
|
11
src/main/java/emu/grasscutter/scripts/data/SceneConfig.java
Normal file
11
src/main/java/emu/grasscutter/scripts/data/SceneConfig.java
Normal file
@ -0,0 +1,11 @@
|
||||
package emu.grasscutter.scripts.data;
|
||||
|
||||
import emu.grasscutter.utils.Position;
|
||||
|
||||
public class SceneConfig {
|
||||
public Position vision_anchor;
|
||||
public Position born_pos;
|
||||
public Position born_rot;
|
||||
public Position begin_pos;
|
||||
public Position size;
|
||||
}
|
12
src/main/java/emu/grasscutter/scripts/data/SceneGadget.java
Normal file
12
src/main/java/emu/grasscutter/scripts/data/SceneGadget.java
Normal file
@ -0,0 +1,12 @@
|
||||
package emu.grasscutter.scripts.data;
|
||||
|
||||
import emu.grasscutter.utils.Position;
|
||||
|
||||
public class SceneGadget {
|
||||
public int level;
|
||||
public int config_id;
|
||||
public int gadget_id;
|
||||
public int state;
|
||||
public Position pos;
|
||||
public Position rot;
|
||||
}
|
33
src/main/java/emu/grasscutter/scripts/data/SceneGroup.java
Normal file
33
src/main/java/emu/grasscutter/scripts/data/SceneGroup.java
Normal file
@ -0,0 +1,33 @@
|
||||
package emu.grasscutter.scripts.data;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import emu.grasscutter.utils.Position;
|
||||
|
||||
public class SceneGroup {
|
||||
public transient int block_id; // Not an actual variable in the scripts but we will keep it here for reference
|
||||
|
||||
public int id;
|
||||
public int refresh_id;
|
||||
public Position pos;
|
||||
|
||||
public List<SceneMonster> monsters;
|
||||
public List<SceneGadget> gadgets;
|
||||
public List<SceneTrigger> triggers;
|
||||
public List<SceneSuite> suites;
|
||||
public SceneInitConfig init_config;
|
||||
|
||||
private transient boolean isLoaded; // Not an actual variable in the scripts either
|
||||
|
||||
public boolean isLoaded() {
|
||||
return isLoaded;
|
||||
}
|
||||
|
||||
public boolean setLoaded(boolean loaded) {
|
||||
return loaded;
|
||||
}
|
||||
|
||||
public SceneSuite getSuiteByIndex(int index) {
|
||||
return suites.get(index - 1);
|
||||
}
|
||||
}
|
@ -0,0 +1,9 @@
|
||||
package emu.grasscutter.scripts.data;
|
||||
|
||||
import emu.grasscutter.utils.Position;
|
||||
|
||||
public class SceneInitConfig {
|
||||
public int suite;
|
||||
public int end_suite;
|
||||
public int rand_suite;
|
||||
}
|
11
src/main/java/emu/grasscutter/scripts/data/SceneMonster.java
Normal file
11
src/main/java/emu/grasscutter/scripts/data/SceneMonster.java
Normal file
@ -0,0 +1,11 @@
|
||||
package emu.grasscutter.scripts.data;
|
||||
|
||||
import emu.grasscutter.utils.Position;
|
||||
|
||||
public class SceneMonster {
|
||||
public int level;
|
||||
public int config_id;
|
||||
public int monster_id;
|
||||
public Position pos;
|
||||
public Position rot;
|
||||
}
|
13
src/main/java/emu/grasscutter/scripts/data/SceneSuite.java
Normal file
13
src/main/java/emu/grasscutter/scripts/data/SceneSuite.java
Normal file
@ -0,0 +1,13 @@
|
||||
package emu.grasscutter.scripts.data;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import emu.grasscutter.utils.Position;
|
||||
|
||||
public class SceneSuite {
|
||||
public List<Integer> monsters;
|
||||
public List<String> triggers;
|
||||
public int rand_weight;
|
||||
|
||||
public transient List<SceneMonster> sceneMonsters;
|
||||
}
|
10
src/main/java/emu/grasscutter/scripts/data/SceneTrigger.java
Normal file
10
src/main/java/emu/grasscutter/scripts/data/SceneTrigger.java
Normal file
@ -0,0 +1,10 @@
|
||||
package emu.grasscutter.scripts.data;
|
||||
|
||||
public class SceneTrigger {
|
||||
public String name;
|
||||
public int config_id;
|
||||
public int event;
|
||||
public String source;
|
||||
public String condition;
|
||||
public String action;
|
||||
}
|
7
src/main/java/emu/grasscutter/scripts/data/SceneVar.java
Normal file
7
src/main/java/emu/grasscutter/scripts/data/SceneVar.java
Normal file
@ -0,0 +1,7 @@
|
||||
package emu.grasscutter.scripts.data;
|
||||
|
||||
public class SceneVar {
|
||||
public String name;
|
||||
public int value;
|
||||
public boolean no_refresh;
|
||||
}
|
47
src/main/java/emu/grasscutter/scripts/data/ScriptArgs.java
Normal file
47
src/main/java/emu/grasscutter/scripts/data/ScriptArgs.java
Normal file
@ -0,0 +1,47 @@
|
||||
package emu.grasscutter.scripts.data;
|
||||
|
||||
public class ScriptArgs {
|
||||
public int param1;
|
||||
public int param2;
|
||||
public int param3;
|
||||
|
||||
public ScriptArgs() {
|
||||
|
||||
}
|
||||
|
||||
public ScriptArgs(int param1) {
|
||||
this.param1 = param1;
|
||||
}
|
||||
|
||||
public ScriptArgs(int param1, int param2) {
|
||||
this.param1 = param1;
|
||||
this.param2 = param2;
|
||||
}
|
||||
|
||||
public int getParam1() {
|
||||
return param1;
|
||||
}
|
||||
|
||||
public ScriptArgs setParam1(int param1) {
|
||||
this.param1 = param1;
|
||||
return this;
|
||||
}
|
||||
|
||||
public int getParam2() {
|
||||
return param2;
|
||||
}
|
||||
|
||||
public ScriptArgs setParam2(int param2) {
|
||||
this.param2 = param2;
|
||||
return this;
|
||||
}
|
||||
|
||||
public int getParam3() {
|
||||
return param3;
|
||||
}
|
||||
|
||||
public ScriptArgs setParam3(int param3) {
|
||||
this.param3 = param3;
|
||||
return this;
|
||||
}
|
||||
}
|
@ -0,0 +1,108 @@
|
||||
package emu.grasscutter.scripts.serializer;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.luaj.vm2.LuaTable;
|
||||
import org.luaj.vm2.LuaValue;
|
||||
|
||||
public class LuaSerializer implements Serializer {
|
||||
|
||||
@Override
|
||||
public <T> List<T> toList(Class<T> type, Object obj) {
|
||||
return serializeList(type, (LuaTable) obj);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> T toObject(Class<T> type, Object obj) {
|
||||
return serialize(type, (LuaTable) obj);
|
||||
}
|
||||
|
||||
public <T> List<T> serializeList(Class<T> type, LuaTable table) {
|
||||
List<T> list = new ArrayList();
|
||||
|
||||
try {
|
||||
LuaValue[] keys = table.keys();
|
||||
for (LuaValue k : keys) {
|
||||
try {
|
||||
LuaValue keyValue = table.get(k);
|
||||
|
||||
T object = null;
|
||||
|
||||
if (keyValue.istable()) {
|
||||
object = serialize(type, keyValue.checktable());
|
||||
} else if (keyValue.isint()) {
|
||||
object = (T) (Integer) keyValue.toint();
|
||||
} else if (keyValue.isnumber()) {
|
||||
object = (T) (Float) keyValue.tofloat(); // terrible...
|
||||
} else if (keyValue.isstring()) {
|
||||
object = (T) keyValue.tojstring();
|
||||
} else {
|
||||
object = (T) keyValue;
|
||||
}
|
||||
|
||||
if (object != null) {
|
||||
list.add(object);
|
||||
}
|
||||
} catch (Exception ex) {
|
||||
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
return list;
|
||||
}
|
||||
|
||||
public <T> T serialize(Class<T> type, LuaTable table) {
|
||||
T object = null;
|
||||
|
||||
if (type == List.class) {
|
||||
try {
|
||||
Class<T> listType = (Class<T>) type.getTypeParameters()[0].getClass();
|
||||
return (T) serializeList(listType, table);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
object = type.getDeclaredConstructor().newInstance(null);
|
||||
|
||||
LuaValue[] keys = table.keys();
|
||||
for (LuaValue k : keys) {
|
||||
try {
|
||||
Field field = object.getClass().getDeclaredField(k.checkjstring());
|
||||
if (field == null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
field.setAccessible(true);
|
||||
LuaValue keyValue = table.get(k);
|
||||
|
||||
if (keyValue.istable()) {
|
||||
field.set(object, serialize(field.getType(), keyValue.checktable()));
|
||||
} else if (field.getType().equals(float.class)) {
|
||||
field.setFloat(object, keyValue.tofloat());
|
||||
} else if (field.getType().equals(int.class)) {
|
||||
field.setInt(object, keyValue.toint());
|
||||
} else if (field.getType().equals(String.class)) {
|
||||
field.set(object, keyValue.tojstring());
|
||||
} else {
|
||||
field.set(object, keyValue);
|
||||
}
|
||||
} catch (Exception ex) {
|
||||
//ex.printStackTrace();
|
||||
continue;
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
return object;
|
||||
}
|
||||
}
|
@ -0,0 +1,12 @@
|
||||
package emu.grasscutter.scripts.serializer;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.luaj.vm2.LuaTable;
|
||||
|
||||
public interface Serializer {
|
||||
|
||||
public <T> List<T> toList(Class<T> type, Object obj);
|
||||
|
||||
public <T> T toObject(Class<T> type, Object obj);
|
||||
}
|
@ -2,6 +2,7 @@ package emu.grasscutter.server.packet.recv;
|
||||
|
||||
import emu.grasscutter.net.packet.Opcodes;
|
||||
import emu.grasscutter.net.packet.PacketOpcodes;
|
||||
import emu.grasscutter.net.proto.DungeonEntryInfoReqOuterClass.DungeonEntryInfoReq;
|
||||
import emu.grasscutter.net.packet.PacketHandler;
|
||||
import emu.grasscutter.server.game.GameSession;
|
||||
|
||||
@ -10,7 +11,9 @@ public class HandlerDungeonEntryInfoReq extends PacketHandler {
|
||||
|
||||
@Override
|
||||
public void handle(GameSession session, byte[] header, byte[] payload) throws Exception {
|
||||
DungeonEntryInfoReq req = DungeonEntryInfoReq.parseFrom(payload);
|
||||
|
||||
session.getServer().getDungeonManager().getEntryInfo(session.getPlayer(), req.getPointId());
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -0,0 +1,25 @@
|
||||
package emu.grasscutter.server.packet.recv;
|
||||
|
||||
import emu.grasscutter.game.entity.EntityAvatar;
|
||||
import emu.grasscutter.net.packet.Opcodes;
|
||||
import emu.grasscutter.net.packet.PacketHandler;
|
||||
import emu.grasscutter.net.packet.PacketOpcodes;
|
||||
import emu.grasscutter.net.proto.EvtAvatarLockChairReqOuterClass.EvtAvatarLockChairReq;
|
||||
import emu.grasscutter.net.proto.PacketHeadOuterClass.PacketHead;
|
||||
import emu.grasscutter.server.game.GameSession;
|
||||
import emu.grasscutter.server.packet.send.PacketEvtAvatarLockChairRsp;
|
||||
|
||||
@Opcodes(PacketOpcodes.EvtAvatarLockChairReq)
|
||||
public class HandlerEvtAvatarLockChairReq extends PacketHandler {
|
||||
|
||||
@Override
|
||||
public void handle(GameSession session, byte[] header, byte[] payload) throws Exception {
|
||||
PacketHead head = PacketHead.parseFrom(header);
|
||||
EvtAvatarLockChairReq lockChairReq = EvtAvatarLockChairReq.parseFrom(payload);
|
||||
|
||||
EntityAvatar entityAvatar = session.getPlayer().getTeamManager().getCurrentAvatarEntity();
|
||||
|
||||
session.send(new PacketEvtAvatarLockChairRsp(head.getClientSequenceId(), entityAvatar, lockChairReq));
|
||||
}
|
||||
|
||||
}
|
@ -1,9 +1,9 @@
|
||||
package emu.grasscutter.server.packet.recv;
|
||||
|
||||
import emu.grasscutter.net.packet.Opcodes;
|
||||
import emu.grasscutter.net.packet.PacketHandler;
|
||||
import emu.grasscutter.net.packet.PacketOpcodes;
|
||||
import emu.grasscutter.net.proto.EvtAvatarSitDownNotifyOuterClass.EvtAvatarSitDownNotify;
|
||||
import emu.grasscutter.net.packet.PacketHandler;
|
||||
import emu.grasscutter.server.game.GameSession;
|
||||
import emu.grasscutter.server.packet.send.PacketEvtAvatarSitDownNotify;
|
||||
|
||||
@ -14,7 +14,7 @@ public class HandlerEvtAvatarSitDownNotify extends PacketHandler {
|
||||
public void handle(GameSession session, byte[] header, byte[] payload) throws Exception {
|
||||
EvtAvatarSitDownNotify notify = EvtAvatarSitDownNotify.parseFrom(payload);
|
||||
|
||||
session.send(new PacketEvtAvatarSitDownNotify(notify));
|
||||
session.getPlayer().getScene().broadcastPacket(new PacketEvtAvatarSitDownNotify(notify));
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -0,0 +1,20 @@
|
||||
package emu.grasscutter.server.packet.recv;
|
||||
|
||||
import emu.grasscutter.net.packet.Opcodes;
|
||||
import emu.grasscutter.net.packet.PacketHandler;
|
||||
import emu.grasscutter.net.packet.PacketOpcodes;
|
||||
import emu.grasscutter.net.proto.EvtAvatarStandUpNotifyOuterClass.EvtAvatarStandUpNotify;
|
||||
import emu.grasscutter.server.game.GameSession;
|
||||
import emu.grasscutter.server.packet.send.PacketEvtAvatarStandUpNotify;
|
||||
|
||||
@Opcodes(PacketOpcodes.EvtAvatarStandUpNotify)
|
||||
public class HandlerEvtAvatarStandUpNotify extends PacketHandler {
|
||||
|
||||
@Override
|
||||
public void handle(GameSession session, byte[] header, byte[] payload) throws Exception {
|
||||
EvtAvatarStandUpNotify notify = EvtAvatarStandUpNotify.parseFrom(payload);
|
||||
|
||||
session.getPlayer().getScene().broadcastPacket(new PacketEvtAvatarStandUpNotify(notify));
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,20 @@
|
||||
package emu.grasscutter.server.packet.recv;
|
||||
|
||||
import emu.grasscutter.net.packet.Opcodes;
|
||||
import emu.grasscutter.net.packet.PacketOpcodes;
|
||||
import emu.grasscutter.net.proto.PlayerEnterDungeonReqOuterClass.PlayerEnterDungeonReq;
|
||||
import emu.grasscutter.net.packet.PacketHandler;
|
||||
import emu.grasscutter.server.game.GameSession;
|
||||
|
||||
@Opcodes(PacketOpcodes.PlayerEnterDungeonReq)
|
||||
public class HandlerPlayerEnterDungeonReq extends PacketHandler {
|
||||
|
||||
@Override
|
||||
public void handle(GameSession session, byte[] header, byte[] payload) throws Exception {
|
||||
// Auto template
|
||||
PlayerEnterDungeonReq req = PlayerEnterDungeonReq.parseFrom(payload);
|
||||
|
||||
session.getServer().getDungeonManager().enterDungeon(session.getPlayer(), req.getPointId(), req.getDungeonId());
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,16 @@
|
||||
package emu.grasscutter.server.packet.recv;
|
||||
|
||||
import emu.grasscutter.net.packet.Opcodes;
|
||||
import emu.grasscutter.net.packet.PacketOpcodes;
|
||||
import emu.grasscutter.net.packet.PacketHandler;
|
||||
import emu.grasscutter.server.game.GameSession;
|
||||
|
||||
@Opcodes(PacketOpcodes.PlayerQuitDungeonReq)
|
||||
public class HandlerPlayerQuitDungeonReq extends PacketHandler {
|
||||
|
||||
@Override
|
||||
public void handle(GameSession session, byte[] header, byte[] payload) throws Exception {
|
||||
session.getPlayer().getServer().getDungeonManager().exitDungeon(session.getPlayer());
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,38 @@
|
||||
package emu.grasscutter.server.packet.recv;
|
||||
|
||||
import emu.grasscutter.game.entity.EntityGadget;
|
||||
import emu.grasscutter.game.entity.GameEntity;
|
||||
import emu.grasscutter.net.packet.Opcodes;
|
||||
import emu.grasscutter.net.packet.PacketOpcodes;
|
||||
import emu.grasscutter.net.proto.SelectWorktopOptionReqOuterClass.SelectWorktopOptionReq;
|
||||
import emu.grasscutter.scripts.constants.EventType;
|
||||
import emu.grasscutter.scripts.data.ScriptArgs;
|
||||
import emu.grasscutter.net.packet.PacketHandler;
|
||||
import emu.grasscutter.server.game.GameSession;
|
||||
import emu.grasscutter.server.packet.send.PacketSelectWorktopOptionRsp;
|
||||
|
||||
@Opcodes(PacketOpcodes.SelectWorktopOptionReq)
|
||||
public class HandlerSelectWorktopOptionReq extends PacketHandler {
|
||||
|
||||
@Override
|
||||
public void handle(GameSession session, byte[] header, byte[] payload) throws Exception {
|
||||
SelectWorktopOptionReq req = SelectWorktopOptionReq.parseFrom(payload);
|
||||
|
||||
try {
|
||||
GameEntity entity = session.getPlayer().getScene().getEntityById(req.getGadgetEntityId());
|
||||
|
||||
if (entity == null || !(entity instanceof EntityGadget)) {
|
||||
return;
|
||||
}
|
||||
|
||||
session.getPlayer().getScene().getScriptManager().callEvent(
|
||||
EventType.EVENT_SELECT_OPTION,
|
||||
new ScriptArgs(entity.getConfigId(), req.getOptionId())
|
||||
);
|
||||
} finally {
|
||||
// Always send packet
|
||||
session.send(new PacketSelectWorktopOptionRsp(req.getGadgetEntityId(), req.getOptionId()));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,21 @@
|
||||
package emu.grasscutter.server.packet.send;
|
||||
|
||||
import emu.grasscutter.game.dungeons.DungeonChallenge;
|
||||
import emu.grasscutter.net.packet.BasePacket;
|
||||
import emu.grasscutter.net.packet.PacketOpcodes;
|
||||
import emu.grasscutter.net.proto.ChallengeDataNotifyOuterClass.ChallengeDataNotify;
|
||||
|
||||
public class PacketChallengeDataNotify extends BasePacket {
|
||||
|
||||
public PacketChallengeDataNotify(DungeonChallenge challenge, int index, int value) {
|
||||
super(PacketOpcodes.ChallengeDataNotify);
|
||||
|
||||
ChallengeDataNotify proto = ChallengeDataNotify.newBuilder()
|
||||
.setChallengeIndex(challenge.getChallengeIndex())
|
||||
.setParamIndex(index)
|
||||
.setValue(value)
|
||||
.build();
|
||||
|
||||
this.setData(proto);
|
||||
}
|
||||
}
|
@ -0,0 +1,21 @@
|
||||
package emu.grasscutter.server.packet.send;
|
||||
|
||||
import emu.grasscutter.game.dungeons.DungeonChallenge;
|
||||
import emu.grasscutter.net.packet.BasePacket;
|
||||
import emu.grasscutter.net.packet.PacketOpcodes;
|
||||
import emu.grasscutter.net.proto.DungeonChallengeBeginNotifyOuterClass.DungeonChallengeBeginNotify;
|
||||
|
||||
public class PacketDungeonChallengeBeginNotify extends BasePacket {
|
||||
|
||||
public PacketDungeonChallengeBeginNotify(DungeonChallenge challenge) {
|
||||
super(PacketOpcodes.DungeonChallengeBeginNotify);
|
||||
|
||||
DungeonChallengeBeginNotify proto = DungeonChallengeBeginNotify.newBuilder()
|
||||
.setChallengeId(challenge.getChallengeId())
|
||||
.setChallengeIndex(challenge.getChallengeIndex())
|
||||
.setGroupId(challenge.getGroup().id)
|
||||
.build();
|
||||
|
||||
this.setData(proto);
|
||||
}
|
||||
}
|
@ -0,0 +1,22 @@
|
||||
package emu.grasscutter.server.packet.send;
|
||||
|
||||
import emu.grasscutter.game.dungeons.DungeonChallenge;
|
||||
import emu.grasscutter.net.packet.BasePacket;
|
||||
import emu.grasscutter.net.packet.PacketOpcodes;
|
||||
import emu.grasscutter.net.proto.DungeonChallengeFinishNotifyOuterClass.DungeonChallengeFinishNotify;
|
||||
|
||||
public class PacketDungeonChallengeFinishNotify extends BasePacket {
|
||||
|
||||
public PacketDungeonChallengeFinishNotify(DungeonChallenge challenge) {
|
||||
super(PacketOpcodes.DungeonChallengeFinishNotify);
|
||||
|
||||
DungeonChallengeFinishNotify proto = DungeonChallengeFinishNotify.newBuilder()
|
||||
.setChallengeIndex(challenge.getChallengeIndex())
|
||||
.setIsSuccess(challenge.isSuccess())
|
||||
.setUnk1(challenge.getChallengeId())
|
||||
.setUnk2(30)
|
||||
.build();
|
||||
|
||||
this.setData(proto);
|
||||
}
|
||||
}
|
@ -0,0 +1,37 @@
|
||||
package emu.grasscutter.server.packet.send;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
import emu.grasscutter.data.common.PointData;
|
||||
import emu.grasscutter.game.player.Player;
|
||||
import emu.grasscutter.net.packet.BasePacket;
|
||||
import emu.grasscutter.net.packet.PacketOpcodes;
|
||||
import emu.grasscutter.net.proto.DungeonEntryInfoOuterClass.DungeonEntryInfo;
|
||||
import emu.grasscutter.net.proto.DungeonEntryInfoRspOuterClass.DungeonEntryInfoRsp;
|
||||
|
||||
public class PacketDungeonEntryInfoRsp extends BasePacket {
|
||||
|
||||
public PacketDungeonEntryInfoRsp(Player player, PointData pointData) {
|
||||
super(PacketOpcodes.DungeonEntryInfoRsp);
|
||||
|
||||
DungeonEntryInfoRsp.Builder proto = DungeonEntryInfoRsp.newBuilder()
|
||||
.setPointId(pointData.getId());
|
||||
|
||||
for (int dungeonId : pointData.getDungeonIds()) {
|
||||
DungeonEntryInfo info = DungeonEntryInfo.newBuilder().setDungeonId(dungeonId).build();
|
||||
proto.addDungeonEntryList(info);
|
||||
}
|
||||
|
||||
this.setData(proto);
|
||||
}
|
||||
|
||||
public PacketDungeonEntryInfoRsp() {
|
||||
super(PacketOpcodes.DungeonEntryInfoRsp);
|
||||
|
||||
DungeonEntryInfoRsp proto = DungeonEntryInfoRsp.newBuilder()
|
||||
.setRetcode(1)
|
||||
.build();
|
||||
|
||||
this.setData(proto);
|
||||
}
|
||||
}
|
@ -0,0 +1,23 @@
|
||||
package emu.grasscutter.server.packet.send;
|
||||
|
||||
import emu.grasscutter.game.entity.EntityAvatar;
|
||||
import emu.grasscutter.net.packet.BasePacket;
|
||||
import emu.grasscutter.net.packet.PacketOpcodes;
|
||||
import emu.grasscutter.net.proto.EvtAvatarLockChairReqOuterClass.EvtAvatarLockChairReq;
|
||||
import emu.grasscutter.net.proto.EvtAvatarLockChairRspOuterClass.EvtAvatarLockChairRsp;
|
||||
import emu.grasscutter.net.proto.RetcodeOuterClass;
|
||||
|
||||
public class PacketEvtAvatarLockChairRsp extends BasePacket {
|
||||
public PacketEvtAvatarLockChairRsp(int clientSequence, EntityAvatar entityAvatar, EvtAvatarLockChairReq lockChairReq) {
|
||||
super(PacketOpcodes.EvtAvatarLockChairRsp);
|
||||
|
||||
EvtAvatarLockChairRsp p = EvtAvatarLockChairRsp.newBuilder()
|
||||
.setRetcode(RetcodeOuterClass.Retcode.RET_SUCC_VALUE)
|
||||
.setEntityId(entityAvatar.getId())
|
||||
.setPosition(lockChairReq.getPosition())
|
||||
.setChairId(lockChairReq.getChairId())
|
||||
.build();
|
||||
|
||||
this.setData(p);
|
||||
}
|
||||
}
|
@ -0,0 +1,21 @@
|
||||
package emu.grasscutter.server.packet.send;
|
||||
|
||||
import emu.grasscutter.net.packet.BasePacket;
|
||||
import emu.grasscutter.net.packet.PacketOpcodes;
|
||||
import emu.grasscutter.net.proto.EvtAvatarStandUpNotifyOuterClass.EvtAvatarStandUpNotify;
|
||||
|
||||
public class PacketEvtAvatarStandUpNotify extends BasePacket {
|
||||
|
||||
public PacketEvtAvatarStandUpNotify(EvtAvatarStandUpNotify notify) {
|
||||
super(PacketOpcodes.EvtAvatarStandUpNotify);
|
||||
|
||||
EvtAvatarStandUpNotify proto = EvtAvatarStandUpNotify.newBuilder()
|
||||
.setEntityId(notify.getEntityId())
|
||||
.setDirection(notify.getDirection())
|
||||
.setPerformID(notify.getPerformID())
|
||||
.setChairId(notify.getChairId())
|
||||
.build();
|
||||
|
||||
this.setData(proto);
|
||||
}
|
||||
}
|
@ -1,6 +1,6 @@
|
||||
package emu.grasscutter.server.packet.send;
|
||||
|
||||
import emu.grasscutter.game.entity.EntityGadget;
|
||||
import emu.grasscutter.game.entity.EntityBaseGadget;
|
||||
import emu.grasscutter.net.packet.BasePacket;
|
||||
import emu.grasscutter.net.packet.PacketOpcodes;
|
||||
import emu.grasscutter.net.proto.GadgetInteractRspOuterClass.GadgetInteractRsp;
|
||||
@ -8,7 +8,7 @@ import emu.grasscutter.net.proto.InteractTypeOuterClass.InteractType;
|
||||
import emu.grasscutter.net.proto.RetcodeOuterClass;
|
||||
|
||||
public class PacketGadgetInteractRsp extends BasePacket {
|
||||
public PacketGadgetInteractRsp(EntityGadget gadget, InteractType interact) {
|
||||
public PacketGadgetInteractRsp(EntityBaseGadget gadget, InteractType interact) {
|
||||
super(PacketOpcodes.GadgetInteractRsp);
|
||||
|
||||
GadgetInteractRsp proto = GadgetInteractRsp.newBuilder()
|
||||
|
@ -0,0 +1,21 @@
|
||||
package emu.grasscutter.server.packet.send;
|
||||
|
||||
import emu.grasscutter.game.entity.EntityGadget;
|
||||
import emu.grasscutter.net.packet.BasePacket;
|
||||
import emu.grasscutter.net.packet.PacketOpcodes;
|
||||
import emu.grasscutter.net.proto.GadgetStateNotifyOuterClass.GadgetStateNotify;
|
||||
|
||||
public class PacketGadgetStateNotify extends BasePacket {
|
||||
|
||||
public PacketGadgetStateNotify(EntityGadget gadget, int newState) {
|
||||
super(PacketOpcodes.GadgetStateNotify);
|
||||
|
||||
GadgetStateNotify proto = GadgetStateNotify.newBuilder()
|
||||
.setGadgetEntityId(gadget.getId())
|
||||
.setGadgetState(newState)
|
||||
.setIsEnableInteract(true)
|
||||
.build();
|
||||
|
||||
this.setData(proto);
|
||||
}
|
||||
}
|
@ -7,7 +7,5 @@ public class PacketPathfindingEnterSceneRsp extends BasePacket {
|
||||
|
||||
public PacketPathfindingEnterSceneRsp(int clientSequence) {
|
||||
super(PacketOpcodes.PathfindingEnterSceneRsp);
|
||||
|
||||
this.buildHeader(clientSequence);
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,19 @@
|
||||
package emu.grasscutter.server.packet.send;
|
||||
|
||||
import emu.grasscutter.net.packet.BasePacket;
|
||||
import emu.grasscutter.net.packet.PacketOpcodes;
|
||||
import emu.grasscutter.net.proto.PlayerEnterDungeonRspOuterClass.PlayerEnterDungeonRsp;
|
||||
|
||||
public class PacketPlayerEnterDungeonRsp extends BasePacket {
|
||||
|
||||
public PacketPlayerEnterDungeonRsp(int pointId, int dungeonId) {
|
||||
super(PacketOpcodes.PlayerEnterDungeonRsp);
|
||||
|
||||
PlayerEnterDungeonRsp proto = PlayerEnterDungeonRsp.newBuilder()
|
||||
.setPointId(pointId)
|
||||
.setDungeonId(dungeonId)
|
||||
.build();
|
||||
|
||||
this.setData(proto);
|
||||
}
|
||||
}
|
@ -0,0 +1,19 @@
|
||||
package emu.grasscutter.server.packet.send;
|
||||
|
||||
import emu.grasscutter.net.packet.BasePacket;
|
||||
import emu.grasscutter.net.packet.PacketOpcodes;
|
||||
import emu.grasscutter.net.proto.SelectWorktopOptionRspOuterClass.SelectWorktopOptionRsp;
|
||||
|
||||
public class PacketSelectWorktopOptionRsp extends BasePacket {
|
||||
|
||||
public PacketSelectWorktopOptionRsp(int entityId, int optionId) {
|
||||
super(PacketOpcodes.SelectWorktopOptionRsp);
|
||||
|
||||
SelectWorktopOptionRsp proto = SelectWorktopOptionRsp.newBuilder()
|
||||
.setGadgetEntityId(entityId)
|
||||
.setOptionId(optionId)
|
||||
.build();
|
||||
|
||||
this.setData(proto);
|
||||
}
|
||||
}
|
@ -0,0 +1,22 @@
|
||||
package emu.grasscutter.server.packet.send;
|
||||
|
||||
import emu.grasscutter.game.entity.EntityGadget;
|
||||
import emu.grasscutter.net.packet.BasePacket;
|
||||
import emu.grasscutter.net.packet.PacketOpcodes;
|
||||
import emu.grasscutter.net.proto.WorktopOptionNotifyOuterClass.WorktopOptionNotify;
|
||||
|
||||
public class PacketWorktopOptionNotify extends BasePacket {
|
||||
|
||||
public PacketWorktopOptionNotify(EntityGadget gadget) {
|
||||
super(PacketOpcodes.WorktopOptionNotify);
|
||||
|
||||
WorktopOptionNotify.Builder proto = WorktopOptionNotify.newBuilder()
|
||||
.setGadgetEntityId(gadget.getId());
|
||||
|
||||
if (gadget.getWorktopOptions() != null) {
|
||||
proto.addAllOptionList(gadget.getWorktopOptions());
|
||||
}
|
||||
|
||||
this.setData(proto);
|
||||
}
|
||||
}
|
@ -67,6 +67,7 @@ public final class Utils {
|
||||
|
||||
private static final char[] HEX_ARRAY = "0123456789abcdef".toCharArray();
|
||||
public static String bytesToHex(byte[] bytes) {
|
||||
if (bytes == null) return "";
|
||||
char[] hexChars = new char[bytes.length * 2];
|
||||
for (int j = 0; j < bytes.length; j++) {
|
||||
int v = bytes[j] & 0xFF;
|
||||
|
Loading…
Reference in New Issue
Block a user