mirror of
https://github.com/Melledy/Grasscutter.git
synced 2024-11-27 19:05:09 +00:00
Merge branch 'development' into api
This commit is contained in:
commit
a1a36dc7a7
@ -115,7 +115,7 @@ There is a dummy user named "Server" in every player's friends list that you can
|
||||
| drop | drop <itemID\|itemName> [amount] | server.drop | Client only | Drops an item around you. | `d` `dropitem` |
|
||||
| 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 |
|
||||
| giveart | giveart [player] \<artifactId> \<mainPropId> [\<appendPropId>[,\<times>]]... [level] | player.giveart | Both side | Gives the player a specified reliquary. | givea |
|
||||
| giveart | giveart [player] \<artifactId> \<mainPropId> [\<appendPropId>[,\<times>]]... [level] | player.giveart | Both side | Gives the player a specified artifact. | gart |
|
||||
| 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 |
|
||||
@ -135,7 +135,7 @@ There is a dummy user named "Server" in every player's friends list that you can
|
||||
| spawn | spanw <entityID\|entityName> [level] [amount] | server.spawn | Client only | Spawns an entity near you | |
|
||||
| stop | stop | server.stop | Both side | Stops the server | |
|
||||
| talent | talent \<talentID> \<value> | player.settalent | Client only | Sets talent level for your currently selected character | |
|
||||
| teleport | teleport \<x> \<y> \<z> | player.teleport | Client only | Change the player's position. | tp |
|
||||
| teleport | teleport [@playerUid] \<x> \<y> \<z> [sceneId] | player.teleport | Both side | Change the player's position. | tp |
|
||||
| tpall | | player.tpall | Client only | Teleports all players in your world to your position | |
|
||||
| weather | weather \<weatherID> \<climateID> | player.weather | Client only | Changes the weather | w |
|
||||
|
||||
@ -144,9 +144,12 @@ There is a dummy user named "Server" in every player's friends list that you can
|
||||
When you want to teleport to somewhere, use the ingame marking function on Map, click Confirm. You will see your
|
||||
character falling from a very high destination, exact location that you marked.
|
||||
|
||||
You can also specify a set Y coordinate by renaming the map marker.
|
||||
|
||||
# Quick Troubleshooting
|
||||
|
||||
* If compiling wasn't successful, please check your JDK installation (JDK 17 and validated JDK's bin PATH variable)
|
||||
* My client doesn't connect, doesn't login, 4206, etc... - Mostly your proxy daemon setup is *the issue*, if using
|
||||
Fiddler make sure it running on another port except 8888
|
||||
* Startup sequence: Mongodb -> Grasscutter -> Proxy daemon (mitmdump, fiddler, etc.) -> Client
|
||||
|
||||
* Startup sequence: Mongodb > Grasscutter > Proxy daemon (mitmdump, fiddler, etc.) > Game
|
||||
|
@ -116,7 +116,7 @@ chmod +x gradlew
|
||||
| drop | drop <物品ID\|物品名称> [数量] | server.drop | 仅客户端 | 在指定玩家周围掉落指定物品 | `d` `dropitem` |
|
||||
| give | give [uid] <物品ID\|物品名称> [数量] [等级] [精炼等级] | | | 给予指定玩家一定数量及等级的物品 (精炼等级仅适用于武器) | `g` `item` `giveitem` |
|
||||
| givechar | givechar \<uid> <角色ID> [等级] | player.givechar | 均可使用 | 给予指定玩家对应角色 | givec |
|
||||
| giveart | giveart [uid] \<圣遗物ID> \<主属性ID> [\<副属性ID>[,<次数>]]... [等级] | player.giveart | 均可使用 | 给予玩家指定属性的圣遗物 | givea |
|
||||
| giveart | giveart [uid] \<圣遗物ID> \<主属性ID> [\<副属性ID>[,<次数>]]... [等级] | player.giveart | 均可使用 | 给予玩家指定属性的圣遗物 | gart |
|
||||
| giveall | giveall [uid] [数量] | player.giveall | 均可使用 | 给予指定玩家全部物品 | givea |
|
||||
| godmode | godmode [uid] | player.godmode | 仅客户端 | 保护你不受到任何伤害(依然会被击退) | |
|
||||
| heal | heal | player.heal | 仅客户端 | 治疗队伍中所有角色 | h |
|
||||
@ -136,7 +136,7 @@ chmod +x gradlew
|
||||
| spawn | spanw <实体ID\|实体名称> [等级] [数量] | server.spawn | 仅客户端 | 在你周围生成实体 | |
|
||||
| stop | stop | server.stop | 均可使用 | 停止服务器 | |
|
||||
| talent | talent <天赋ID> <等级> | player.settalent | 仅客户端 | 设置当前角色的天赋等级 | |
|
||||
| teleport | teleport \<x> \<y> \<z> | player.teleport | 仅客户端 | 传送玩家到指定坐标 | tp |
|
||||
| teleport | teleport [@playerUid] \<x> \<y> \<z> [sceneId] | player.teleport | 均可使用 | 传送玩家到指定坐标 | tp |
|
||||
| tpall | | player.tpall | 仅客户端 | 传送多人世界中所有的玩家到自身地点 | |
|
||||
| weather | weather <天气ID> <气候ID> | player.weather | 仅客户端 | 改变天气 | w |
|
||||
|
||||
|
16
proto/GetFriendShowAvatarInfoReq.proto
Normal file
16
proto/GetFriendShowAvatarInfoReq.proto
Normal file
@ -0,0 +1,16 @@
|
||||
syntax = "proto3";
|
||||
|
||||
option java_package = "emu.grasscutter.net.proto";
|
||||
|
||||
message GetFriendShowAvatarInfoReq {
|
||||
enum CmdId {
|
||||
option allow_alias = true;
|
||||
ENET_CHANNEL_ID = 0;
|
||||
NONE = 0;
|
||||
ENET_IS_RELIABLE = 1;
|
||||
IS_ALLOW_CLIENT = 1;
|
||||
CMD_ID = 4007;
|
||||
}
|
||||
|
||||
uint32 uid = 1;
|
||||
}
|
19
proto/GetFriendShowAvatarInfoRsp.proto
Normal file
19
proto/GetFriendShowAvatarInfoRsp.proto
Normal file
@ -0,0 +1,19 @@
|
||||
syntax = "proto3";
|
||||
|
||||
option java_package = "emu.grasscutter.net.proto";
|
||||
|
||||
import "ShowAvatarInfo.proto";
|
||||
|
||||
message GetFriendShowAvatarInfoRsp {
|
||||
enum CmdId {
|
||||
option allow_alias = true;
|
||||
NONE = 0;
|
||||
ENET_CHANNEL_ID = 0;
|
||||
ENET_IS_RELIABLE = 1;
|
||||
CMD_ID = 4008;
|
||||
}
|
||||
|
||||
int32 retcode = 1;
|
||||
uint32 uid = 2;
|
||||
repeated ShowAvatarInfo show_avatar_info_list = 3;
|
||||
}
|
24
proto/ShowAvatarInfo.proto
Normal file
24
proto/ShowAvatarInfo.proto
Normal file
@ -0,0 +1,24 @@
|
||||
syntax = "proto3";
|
||||
|
||||
option java_package = "emu.grasscutter.net.proto";
|
||||
|
||||
import "AvatarFetterInfo.proto";
|
||||
import "AvatarExcelInfo.proto";
|
||||
import "PropValue.proto";
|
||||
import "ShowEquip.proto";
|
||||
|
||||
message ShowAvatarInfo {
|
||||
uint32 avatar_id = 1;
|
||||
map<uint32, PropValue> prop_map = 2;
|
||||
repeated uint32 talent_id_list = 3;
|
||||
map<uint32, float> fight_prop_map = 4;
|
||||
uint32 skill_depot_id = 5;
|
||||
uint32 core_proud_skill_level = 6;
|
||||
repeated uint32 inherent_proud_skill_list = 7;
|
||||
map<uint32, uint32> skill_level_map = 8;
|
||||
map<uint32, uint32> proud_skill_extra_level_map = 9;
|
||||
repeated ShowEquip equip_list = 10;
|
||||
AvatarFetterInfo fetter_info = 11;
|
||||
uint32 costume_id = 12;
|
||||
AvatarExcelInfo excel_info = 13;
|
||||
}
|
14
proto/ShowEquip.proto
Normal file
14
proto/ShowEquip.proto
Normal file
@ -0,0 +1,14 @@
|
||||
syntax = "proto3";
|
||||
|
||||
option java_package = "emu.grasscutter.net.proto";
|
||||
|
||||
import "Reliquary.proto";
|
||||
import "Weapon.proto";
|
||||
|
||||
message ShowEquip {
|
||||
oneof Detail {
|
||||
Reliquary reliquary = 2;
|
||||
Weapon weapon = 3;
|
||||
}
|
||||
uint32 item_id = 1;
|
||||
}
|
@ -1,5 +1,7 @@
|
||||
package emu.grasscutter;
|
||||
|
||||
import emu.grasscutter.game.mail.Mail;
|
||||
|
||||
public final class Config {
|
||||
|
||||
public String DatabaseUrl = "mongodb://localhost:27017";
|
||||
@ -71,10 +73,15 @@ public final class Config {
|
||||
public int MaxAvatarsInTeamMultiplayer = 4;
|
||||
public int MaxEntityLimit = 1000; // Max entity limit per world. // TODO: Enforce later.
|
||||
public boolean WatchGacha = false;
|
||||
public String ServerNickname = "Server";
|
||||
public int ServerAvatarId = 10000007;
|
||||
public int[] WelcomeEmotes = {2007, 1002, 4010};
|
||||
public String WelcomeMotd = "Welcome to Grasscutter emu";
|
||||
public String WelcomeMailContent = "Hi there!\r\nFirst of all, welcome to Grasscutter. If you have any issues, please let us know so that Lawnmower can help you! \r\n\r\nCheck out our:\r\n<type=\"browser\" text=\"Discord\" href=\"https://discord.gg/T5vZU6UyeG\"/> <type=\"browser\" text=\"GitHub\" href=\"https://github.com/Melledy/Grasscutter\"/>";
|
||||
public int[] WelcomeMailItems = {13509};
|
||||
public Mail.MailItem[] WelcomeMailItems = {
|
||||
new Mail.MailItem(13509, 1, 1),
|
||||
new Mail.MailItem(201, 10000, 1),
|
||||
};
|
||||
|
||||
public boolean EnableOfficialShop = true;
|
||||
|
||||
|
@ -11,6 +11,8 @@ public final class GameConstants {
|
||||
public static final int MAX_TEAMS = 4;
|
||||
public static final int MAIN_CHARACTER_MALE = 10000005;
|
||||
public static final int MAIN_CHARACTER_FEMALE = 10000007;
|
||||
public static final String SERVER_AVATAR_NAME = Grasscutter.getConfig().getGameServerOptions().ServerNickname;
|
||||
public static final int SERVER_AVATAR_ID = Grasscutter.getConfig().getGameServerOptions().ServerAvatarId;
|
||||
public static final Position START_POSITION = new Position(2747, 194, -1719);
|
||||
|
||||
public static final int MAX_FRIENDS = 45;
|
||||
|
@ -6,6 +6,7 @@ import java.io.FileReader;
|
||||
import java.io.FileWriter;
|
||||
import java.io.InputStreamReader;
|
||||
import java.net.InetSocketAddress;
|
||||
import java.util.Calendar;
|
||||
|
||||
import emu.grasscutter.command.CommandMap;
|
||||
import emu.grasscutter.plugin.PluginManager;
|
||||
@ -32,6 +33,8 @@ public final class Grasscutter {
|
||||
private static final Gson gson = new GsonBuilder().setPrettyPrinting().create();
|
||||
private static final File configFile = new File("./config.json");
|
||||
|
||||
private static int day; // Current day of week
|
||||
|
||||
public static RunMode MODE = RunMode.BOTH;
|
||||
private static DispatchServer dispatchServer;
|
||||
private static GameServer gameServer;
|
||||
@ -67,8 +70,10 @@ public final class Grasscutter {
|
||||
Grasscutter.getLogger().info("Starting Grasscutter...");
|
||||
|
||||
// Load all resources.
|
||||
Grasscutter.updateDayOfWeek();
|
||||
ResourceLoader.loadAll();
|
||||
ScriptLoader.init();
|
||||
|
||||
// Database
|
||||
DatabaseManager.initialize();
|
||||
|
||||
@ -179,4 +184,13 @@ public final class Grasscutter {
|
||||
public static PluginManager getPluginManager() {
|
||||
return pluginManager;
|
||||
}
|
||||
|
||||
public static void updateDayOfWeek() {
|
||||
Calendar calendar = Calendar.getInstance();
|
||||
day = calendar.get(Calendar.DAY_OF_WEEK);
|
||||
}
|
||||
|
||||
public static int getCurrentDayOfWeek() {
|
||||
return day;
|
||||
}
|
||||
}
|
||||
|
@ -98,16 +98,16 @@ public final class GiveAllCommand implements CommandHandler {
|
||||
if (isTestItem(itemdata.getId())) continue;
|
||||
|
||||
if (itemdata.isEquip()) {
|
||||
if (itemdata.getItemType() == ItemType.ITEM_WEAPON) {
|
||||
for (int i = 0; i < 5; ++i) {
|
||||
GameItem item = new GameItem(itemdata);
|
||||
if (itemdata.getItemType() == ItemType.ITEM_WEAPON) {
|
||||
item.setLevel(90);
|
||||
item.setPromoteLevel(6);
|
||||
item.setRefinement(4);
|
||||
}
|
||||
itemList.add(item);
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
GameItem item = new GameItem(itemdata);
|
||||
item.setCount(amount);
|
||||
|
@ -14,13 +14,13 @@ import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
@Command(label = "giveart", usage = "giveart [player] <artifactId> <mainPropId> [<appendPropId>[,<times>]]... [level]", description = "Gives the player a specified reliquary", aliases = {"givea"}, permission = "player.giveart")
|
||||
@Command(label = "giveart", usage = "giveart [player] <artifactId> <mainPropId> [<appendPropId>[,<times>]]... [level]", description = "Gives the player a specified artifact", aliases = {"gart"}, permission = "player.giveart")
|
||||
public final class GiveArtifactCommand implements CommandHandler {
|
||||
@Override
|
||||
public void execute(Player sender, List<String> args) {
|
||||
int size = args.size(), target, itemId, mainPropId, level;
|
||||
int size = args.size(), target, itemId, mainPropId, level = 1;
|
||||
ArrayList<Integer> appendPropIdList = new ArrayList<>();
|
||||
String msg = "Usage: giveart|givea [player] <artifactId> <mainPropId> [<appendPropId>[,<times>]]... [level]";
|
||||
String msg = "Usage: giveart|gart [player] <artifactId> <mainPropId> [<appendPropId>[,<times>]]... [level]";
|
||||
|
||||
if (sender == null && size < 2) {
|
||||
CommandHandler.sendMessage(null, msg);
|
||||
@ -29,9 +29,14 @@ public final class GiveArtifactCommand implements CommandHandler {
|
||||
|
||||
if (size >= 2) {
|
||||
try {
|
||||
level = Integer.parseInt(args.get(size - 1));
|
||||
if (level <= 21) size--;
|
||||
else level = 1;
|
||||
try {
|
||||
int last = Integer.parseInt(args.get(size - 1));
|
||||
if (last >= 1 && last <= 21) {
|
||||
level = last;
|
||||
size--;
|
||||
}
|
||||
} catch (NumberFormatException ignored) {
|
||||
}
|
||||
target = Integer.parseInt(args.get(0));
|
||||
int fromIdx;
|
||||
if (Grasscutter.getGameServer().getPlayerByUid(target) == null && sender != null) {
|
||||
@ -79,6 +84,7 @@ public final class GiveArtifactCommand implements CommandHandler {
|
||||
GameItem item = new GameItem(itemData);
|
||||
item.setLevel(level);
|
||||
item.setMainPropId(mainPropId);
|
||||
item.getAppendPropIdList().clear();
|
||||
item.getAppendPropIdList().addAll(appendPropIdList);
|
||||
targetPlayer.getInventory().addItem(item, ActionReason.SubfieldDrop);
|
||||
|
||||
|
@ -163,20 +163,28 @@ public final class GiveCommand implements CommandHandler {
|
||||
List<GameItem> items = new LinkedList<>();
|
||||
for (int i = 0; i < amount; i++) {
|
||||
GameItem item = new GameItem(itemData);
|
||||
if (item.isEquipped()) {
|
||||
// check item max level
|
||||
if (item.getItemType() == ItemType.ITEM_WEAPON) {
|
||||
if (lvl > 90) lvl = 90;
|
||||
} else {
|
||||
if (lvl > 21) lvl = 21;
|
||||
}
|
||||
}
|
||||
item.setCount(amount);
|
||||
item.setLevel(lvl);
|
||||
if (lvl > 20 && lvl < 40) {
|
||||
item.setPromoteLevel(1);
|
||||
} else if (lvl > 40 && lvl <= 50) {
|
||||
item.setPromoteLevel(2);
|
||||
} else if (lvl > 50 && lvl <= 60) {
|
||||
item.setPromoteLevel(3);
|
||||
} else if (lvl > 60 && lvl <= 70) {
|
||||
item.setPromoteLevel(4);
|
||||
} else if (lvl > 70 && lvl <= 80) {
|
||||
item.setPromoteLevel(5);
|
||||
} else if (lvl > 80 && lvl <= 90) {
|
||||
if (lvl > 80) {
|
||||
item.setPromoteLevel(6);
|
||||
} else if (lvl > 70) {
|
||||
item.setPromoteLevel(5);
|
||||
} else if (lvl > 60) {
|
||||
item.setPromoteLevel(4);
|
||||
} else if (lvl > 50) {
|
||||
item.setPromoteLevel(3);
|
||||
} else if (lvl > 40) {
|
||||
item.setPromoteLevel(2);
|
||||
} else if (lvl > 20) {
|
||||
item.setPromoteLevel(1);
|
||||
}
|
||||
if (item.getItemType() == ItemType.ITEM_WEAPON) {
|
||||
if (refinement > 0) {
|
||||
|
@ -1,5 +1,6 @@
|
||||
package emu.grasscutter.command.commands;
|
||||
|
||||
import emu.grasscutter.Grasscutter;
|
||||
import emu.grasscutter.command.Command;
|
||||
import emu.grasscutter.command.CommandHandler;
|
||||
import emu.grasscutter.game.player.Player;
|
||||
@ -7,21 +8,39 @@ import emu.grasscutter.utils.Position;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@Command(label = "teleport", usage = "teleport <x> <y> <z>", aliases = {"tp"},
|
||||
@Command(label = "teleport", usage = "teleport [@player id] <x> <y> <z> [scene id]", aliases = {"tp"},
|
||||
description = "Change the player's position.", permission = "player.teleport")
|
||||
public final class TeleportCommand implements CommandHandler {
|
||||
|
||||
@Override
|
||||
public void execute(Player sender, List<String> args) {
|
||||
if (sender == null) {
|
||||
CommandHandler.sendMessage(null, "Run this command in-game.");
|
||||
int target;
|
||||
if (args.size() < (sender == null ? 4 : 3)) {
|
||||
CommandHandler.sendMessage(sender, sender == null ? "Usage: /tp @<player id> <x> <y> <z> [scene id]" :
|
||||
"Usage: /tp [@<player id>] <x> <y> <z> [scene id]");
|
||||
return;
|
||||
}
|
||||
if (args.get(0).startsWith("@")) {
|
||||
try {
|
||||
target = Integer.parseInt(args.get(0).substring(1));
|
||||
} catch (NumberFormatException e) {
|
||||
CommandHandler.sendMessage(sender, "Invalid player id.");
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
if (sender == null) {
|
||||
CommandHandler.sendMessage(null, "You must specify a player id.");
|
||||
return;
|
||||
}
|
||||
target = sender.getUid();
|
||||
}
|
||||
|
||||
if (args.size() < 3){
|
||||
CommandHandler.sendMessage(sender, "Usage: /tp <x> <y> <z> [scene id]");
|
||||
Player targetPlayer = Grasscutter.getGameServer().getPlayerByUid(target);
|
||||
if (targetPlayer == null) {
|
||||
CommandHandler.sendMessage(sender, "Player not found or offline.");
|
||||
return;
|
||||
}
|
||||
args = args.subList(args.get(0).startsWith("@") ? 1 : 0, args.size());
|
||||
|
||||
try {
|
||||
float x = 0f;
|
||||
@ -29,39 +48,41 @@ public final class TeleportCommand implements CommandHandler {
|
||||
float z = 0f;
|
||||
if (args.get(0).contains("~")) {
|
||||
if (args.get(0).equals("~")) {
|
||||
x = sender.getPos().getX();
|
||||
x = targetPlayer.getPos().getX();
|
||||
} else {
|
||||
x = Float.parseFloat(args.get(0).replace("~", "")) + sender.getPos().getX();
|
||||
x = Float.parseFloat(args.get(0).replace("~", "")) + targetPlayer.getPos().getX();
|
||||
}
|
||||
} else {
|
||||
x = Float.parseFloat(args.get(0));
|
||||
}
|
||||
if (args.get(1).contains("~")) {
|
||||
if (args.get(1).equals("~")) {
|
||||
y = sender.getPos().getY();
|
||||
y = targetPlayer.getPos().getY();
|
||||
} else {
|
||||
y = Float.parseFloat(args.get(1).replace("~", "")) + sender.getPos().getY();
|
||||
y = Float.parseFloat(args.get(1).replace("~", "")) + targetPlayer.getPos().getY();
|
||||
}
|
||||
} else {
|
||||
y = Float.parseFloat(args.get(1));
|
||||
}
|
||||
if (args.get(2).contains("~")) {
|
||||
if (args.get(2).equals("~")) {
|
||||
z = sender.getPos().getZ();
|
||||
z = targetPlayer.getPos().getZ();
|
||||
} else {
|
||||
z = Float.parseFloat(args.get(2).replace("~", "")) + sender.getPos().getZ();
|
||||
z = Float.parseFloat(args.get(2).replace("~", "")) + targetPlayer.getPos().getZ();
|
||||
}
|
||||
} else {
|
||||
z = Float.parseFloat(args.get(2));
|
||||
}
|
||||
int sceneId = sender.getSceneId();
|
||||
int sceneId = targetPlayer.getSceneId();
|
||||
if (args.size() == 4){
|
||||
sceneId = Integer.parseInt(args.get(3));
|
||||
}
|
||||
Position target = new Position(x, y, z);
|
||||
boolean result = sender.getWorld().transferPlayerToScene(sender, sceneId, target);
|
||||
Position target_pos = new Position(x, y, z);
|
||||
boolean result = targetPlayer.getWorld().transferPlayerToScene(targetPlayer, sceneId, target_pos);
|
||||
if (!result) {
|
||||
CommandHandler.sendMessage(sender, "Invalid position.");
|
||||
} else {
|
||||
CommandHandler.sendMessage(sender, "Teleported " + targetPlayer.getNickname() + " to " + x + "," + y + "," + z + " in scene " + sceneId);
|
||||
}
|
||||
} catch (NumberFormatException ignored) {
|
||||
CommandHandler.sendMessage(sender, "Invalid position.");
|
||||
|
@ -15,6 +15,8 @@ import emu.grasscutter.data.def.*;
|
||||
import it.unimi.dsi.fastutil.ints.Int2ObjectLinkedOpenHashMap;
|
||||
import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
|
||||
import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap;
|
||||
import it.unimi.dsi.fastutil.ints.IntArrayList;
|
||||
import it.unimi.dsi.fastutil.ints.IntList;
|
||||
|
||||
public class GameData {
|
||||
// BinOutputs
|
||||
@ -61,12 +63,14 @@ 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<DailyDungeonData> dailyDungeonDataMap = 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<>();
|
||||
private static final IntList scenePointIdList = new IntArrayList();
|
||||
|
||||
public static char EJWOA = 's';
|
||||
|
||||
@ -280,6 +284,10 @@ public class GameData {
|
||||
return dungeonDataMap;
|
||||
}
|
||||
|
||||
public static Int2ObjectMap<DailyDungeonData> getDailyDungeonDataMap() {
|
||||
return dailyDungeonDataMap;
|
||||
}
|
||||
|
||||
public static Map<Integer, List<ShopGoodsData>> getShopGoodsDataEntries() {
|
||||
if (shopGoods.isEmpty()) {
|
||||
shopGoodsDataMap.forEach((k, v) -> {
|
||||
@ -291,4 +299,8 @@ public class GameData {
|
||||
|
||||
return shopGoods;
|
||||
}
|
||||
|
||||
public static IntList getScenePointIdList() {
|
||||
return scenePointIdList;
|
||||
}
|
||||
}
|
||||
|
@ -48,11 +48,12 @@ public class ResourceLoader {
|
||||
loadOpenConfig();
|
||||
// Load resources
|
||||
loadResources();
|
||||
loadScenePoints();
|
||||
// Process into depots
|
||||
GameDepot.load();
|
||||
// Load spawn data
|
||||
loadSpawnData();
|
||||
// Load scene points - must be done AFTER resources are loaded
|
||||
loadScenePoints();
|
||||
// Custom - TODO move this somewhere else
|
||||
try {
|
||||
GameData.getAvatarSkillDepotDataMap().get(504).setAbilities(
|
||||
@ -168,6 +169,9 @@ public class ResourceLoader {
|
||||
|
||||
ScenePointEntry sl = new ScenePointEntry(sceneId + "_" + entry.getKey(), pointData);
|
||||
scenePointList.add(sl);
|
||||
GameData.getScenePointIdList().add(pointData.getId());
|
||||
|
||||
pointData.updateDailyDungeon();
|
||||
}
|
||||
|
||||
for (ScenePointEntry entry : scenePointList) {
|
||||
|
@ -1,12 +1,18 @@
|
||||
package emu.grasscutter.data.common;
|
||||
|
||||
import emu.grasscutter.Grasscutter;
|
||||
import emu.grasscutter.data.GameData;
|
||||
import emu.grasscutter.data.def.DailyDungeonData;
|
||||
import emu.grasscutter.utils.Position;
|
||||
import it.unimi.dsi.fastutil.ints.IntArrayList;
|
||||
import it.unimi.dsi.fastutil.ints.IntList;
|
||||
|
||||
public class PointData {
|
||||
private int id;
|
||||
private String $type;
|
||||
private Position tranPos;
|
||||
private int[] dungeonIds;
|
||||
private int[] dungeonRandomList;
|
||||
|
||||
public int getId() {
|
||||
return id;
|
||||
@ -27,4 +33,31 @@ public class PointData {
|
||||
public int[] getDungeonIds() {
|
||||
return dungeonIds;
|
||||
}
|
||||
|
||||
public int[] getDungeonRandomList() {
|
||||
return dungeonRandomList;
|
||||
}
|
||||
|
||||
public void updateDailyDungeon() {
|
||||
if (getDungeonRandomList() == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
IntList newDungeons = new IntArrayList();
|
||||
int day = Grasscutter.getCurrentDayOfWeek();
|
||||
|
||||
for (int randomId : getDungeonRandomList()) {
|
||||
DailyDungeonData data = GameData.getDailyDungeonDataMap().get(randomId);
|
||||
|
||||
if (data != null) {
|
||||
int[] addDungeons = data.getDungeonsByDay(day);
|
||||
|
||||
for (int d : addDungeons) {
|
||||
newDungeons.add(d);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
this.dungeonIds = newDungeons.toIntArray();
|
||||
}
|
||||
}
|
||||
|
50
src/main/java/emu/grasscutter/data/def/DailyDungeonData.java
Normal file
50
src/main/java/emu/grasscutter/data/def/DailyDungeonData.java
Normal file
@ -0,0 +1,50 @@
|
||||
package emu.grasscutter.data.def;
|
||||
|
||||
import java.util.Calendar;
|
||||
|
||||
import emu.grasscutter.data.GameData;
|
||||
import emu.grasscutter.data.GameResource;
|
||||
import emu.grasscutter.data.ResourceType;
|
||||
|
||||
import emu.grasscutter.game.props.SceneType;
|
||||
import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
|
||||
import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap;
|
||||
|
||||
@ResourceType(name = "DailyDungeonConfigData.json")
|
||||
public class DailyDungeonData extends GameResource {
|
||||
private int Id;
|
||||
private int[] Monday;
|
||||
private int[] Tuesday;
|
||||
private int[] Wednesday;
|
||||
private int[] Thursday;
|
||||
private int[] Friday;
|
||||
private int[] Saturday;
|
||||
private int[] Sunday;
|
||||
|
||||
private static final int[] empty = new int[0];
|
||||
private final Int2ObjectMap<int[]> map;
|
||||
|
||||
public DailyDungeonData() {
|
||||
this.map = new Int2ObjectOpenHashMap<>();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getId() {
|
||||
return this.Id;
|
||||
}
|
||||
|
||||
public int[] getDungeonsByDay(int day) {
|
||||
return map.getOrDefault(day, empty);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onLoad() {
|
||||
map.put(Calendar.MONDAY, Monday);
|
||||
map.put(Calendar.TUESDAY, Tuesday);
|
||||
map.put(Calendar.WEDNESDAY, Wednesday);
|
||||
map.put(Calendar.THURSDAY, Thursday);
|
||||
map.put(Calendar.FRIDAY, Friday);
|
||||
map.put(Calendar.SATURDAY, Saturday);
|
||||
map.put(Calendar.SUNDAY, Sunday);
|
||||
}
|
||||
}
|
@ -104,7 +104,10 @@ public class Account {
|
||||
}
|
||||
|
||||
public boolean hasPermission(String permission) {
|
||||
return this.permissions.contains(permission) || this.permissions.contains("*");
|
||||
return this.permissions.contains(permission) ||
|
||||
this.permissions.contains("*") ||
|
||||
(this.permissions.contains("player") || this.permissions.contains("player.*")) && permission.startsWith("player.") ||
|
||||
(this.permissions.contains("server") || this.permissions.contains("server.*")) && permission.startsWith("server.");
|
||||
}
|
||||
|
||||
public boolean removePermission(String permission) {
|
||||
|
@ -15,7 +15,6 @@ import dev.morphia.annotations.Indexed;
|
||||
import dev.morphia.annotations.PostLoad;
|
||||
import dev.morphia.annotations.PrePersist;
|
||||
import dev.morphia.annotations.Transient;
|
||||
import emu.grasscutter.Grasscutter;
|
||||
import emu.grasscutter.data.GameData;
|
||||
import emu.grasscutter.data.common.FightPropData;
|
||||
import emu.grasscutter.data.custom.OpenConfigEntry;
|
||||
@ -26,18 +25,19 @@ import emu.grasscutter.data.def.AvatarSkillDepotData;
|
||||
import emu.grasscutter.data.def.AvatarSkillDepotData.InherentProudSkillOpens;
|
||||
import emu.grasscutter.data.def.AvatarTalentData;
|
||||
import emu.grasscutter.data.def.EquipAffixData;
|
||||
import emu.grasscutter.data.def.ItemData.WeaponProperty;
|
||||
import emu.grasscutter.data.def.ProudSkillData;
|
||||
import emu.grasscutter.data.def.ReliquaryAffixData;
|
||||
import emu.grasscutter.data.def.ReliquaryLevelData;
|
||||
import emu.grasscutter.data.def.ReliquaryMainPropData;
|
||||
import emu.grasscutter.data.def.ReliquarySetData;
|
||||
import emu.grasscutter.data.def.WeaponCurveData;
|
||||
import emu.grasscutter.data.def.WeaponPromoteData;
|
||||
import emu.grasscutter.data.def.ItemData.WeaponProperty;
|
||||
import emu.grasscutter.data.def.ProudSkillData;
|
||||
import emu.grasscutter.database.DatabaseHelper;
|
||||
import emu.grasscutter.game.entity.EntityAvatar;
|
||||
import emu.grasscutter.game.inventory.EquipType;
|
||||
import emu.grasscutter.game.inventory.GameItem;
|
||||
import emu.grasscutter.game.inventory.ItemType;
|
||||
import emu.grasscutter.game.player.Player;
|
||||
import emu.grasscutter.game.props.ElementType;
|
||||
import emu.grasscutter.game.props.EntityIdType;
|
||||
@ -45,8 +45,11 @@ import emu.grasscutter.game.props.FetterState;
|
||||
import emu.grasscutter.game.props.FightProperty;
|
||||
import emu.grasscutter.game.props.PlayerProperty;
|
||||
import emu.grasscutter.net.proto.AvatarFetterInfoOuterClass.AvatarFetterInfo;
|
||||
import emu.grasscutter.net.proto.FetterDataOuterClass.FetterData;
|
||||
import emu.grasscutter.net.proto.AvatarInfoOuterClass.AvatarInfo;
|
||||
import emu.grasscutter.net.proto.FetterDataOuterClass.FetterData;
|
||||
import emu.grasscutter.net.proto.ShowAvatarInfoOuterClass;
|
||||
import emu.grasscutter.net.proto.ShowAvatarInfoOuterClass.ShowAvatarInfo;
|
||||
import emu.grasscutter.net.proto.ShowEquipOuterClass.ShowEquip;
|
||||
import emu.grasscutter.server.packet.send.PacketAbilityChangeNotify;
|
||||
import emu.grasscutter.server.packet.send.PacketAvatarEquipChangeNotify;
|
||||
import emu.grasscutter.server.packet.send.PacketAvatarFightPropNotify;
|
||||
@ -798,6 +801,46 @@ public class Avatar {
|
||||
return avatarInfo.build();
|
||||
}
|
||||
|
||||
// used only in character showcase
|
||||
public ShowAvatarInfo toShowAvatarInfoProto() {
|
||||
AvatarFetterInfo.Builder avatarFetter = AvatarFetterInfo.newBuilder()
|
||||
.setExpLevel(this.getFetterLevel());
|
||||
|
||||
ShowAvatarInfo.Builder showAvatarInfo = ShowAvatarInfoOuterClass.ShowAvatarInfo.newBuilder()
|
||||
.setAvatarId(avatarId)
|
||||
.addAllTalentIdList(this.getTalentIdList())
|
||||
.putAllFightPropMap(this.getFightProperties())
|
||||
.setSkillDepotId(this.getSkillDepotId())
|
||||
.setCoreProudSkillLevel(this.getCoreProudSkillLevel())
|
||||
.addAllInherentProudSkillList(this.getProudSkillList())
|
||||
.putAllSkillLevelMap(this.getSkillLevelMap())
|
||||
.putAllProudSkillExtraLevelMap(this.getProudSkillBonusMap())
|
||||
.setFetterInfo(avatarFetter)
|
||||
.setCostumeId(this.getCostume());
|
||||
|
||||
showAvatarInfo.putPropMap(PlayerProperty.PROP_LEVEL.getId(), ProtoHelper.newPropValue(PlayerProperty.PROP_LEVEL, this.getLevel()));
|
||||
showAvatarInfo.putPropMap(PlayerProperty.PROP_EXP.getId(), ProtoHelper.newPropValue(PlayerProperty.PROP_EXP, this.getExp()));
|
||||
showAvatarInfo.putPropMap(PlayerProperty.PROP_BREAK_LEVEL.getId(), ProtoHelper.newPropValue(PlayerProperty.PROP_BREAK_LEVEL, this.getPromoteLevel()));
|
||||
showAvatarInfo.putPropMap(PlayerProperty.PROP_SATIATION_VAL.getId(), ProtoHelper.newPropValue(PlayerProperty.PROP_SATIATION_VAL, this.getSatiation()));
|
||||
showAvatarInfo.putPropMap(PlayerProperty.PROP_SATIATION_PENALTY_TIME.getId(), ProtoHelper.newPropValue(PlayerProperty.PROP_SATIATION_VAL, this.getSatiationPenalty()));
|
||||
int maxStamina = this.getPlayer().getProperty(PlayerProperty.PROP_MAX_STAMINA);
|
||||
showAvatarInfo.putPropMap(PlayerProperty.PROP_MAX_STAMINA.getId(), ProtoHelper.newPropValue(PlayerProperty.PROP_MAX_STAMINA, maxStamina));
|
||||
|
||||
for (GameItem item : this.getEquips().values()) {
|
||||
if (item.getItemType() == ItemType.ITEM_RELIQUARY) {
|
||||
showAvatarInfo.addEquipList(ShowEquip.newBuilder()
|
||||
.setItemId(item.getItemId())
|
||||
.setReliquary(item.toReliquaryProto()));
|
||||
} else if (item.getItemType() == ItemType.ITEM_WEAPON) {
|
||||
showAvatarInfo.addEquipList(ShowEquip.newBuilder()
|
||||
.setItemId(item.getItemId())
|
||||
.setWeapon(item.toWeaponProto()));
|
||||
}
|
||||
}
|
||||
|
||||
return showAvatarInfo.build();
|
||||
}
|
||||
|
||||
@PostLoad
|
||||
private void onLoad() {
|
||||
|
||||
|
@ -28,7 +28,7 @@ public class DungeonManager {
|
||||
public void getEntryInfo(Player player, int pointId) {
|
||||
ScenePointEntry entry = GameData.getScenePointEntryById(player.getScene().getId(), pointId);
|
||||
|
||||
if (entry == null || entry.getPointData().getDungeonIds() == null) {
|
||||
if (entry == null) {
|
||||
// Error
|
||||
player.sendPacket(new PacketDungeonEntryInfoRsp());
|
||||
return;
|
||||
@ -79,4 +79,10 @@ public class DungeonManager {
|
||||
player.getWorld().transferPlayerToScene(player, prevScene, prevPos);
|
||||
player.sendPacket(new BasePacket(PacketOpcodes.PlayerQuitDungeonRsp));
|
||||
}
|
||||
|
||||
public void updateDailyDungeons() {
|
||||
for (ScenePointEntry entry : GameData.getScenePointEntries().values()) {
|
||||
entry.getPointData().updateDailyDungeon();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -34,6 +34,10 @@ public abstract class GameEntity {
|
||||
return this.id;
|
||||
}
|
||||
|
||||
public int getEntityType() {
|
||||
return getId() >> 24;
|
||||
}
|
||||
|
||||
public World getWorld() {
|
||||
return this.getScene().getWorld();
|
||||
}
|
||||
|
@ -375,13 +375,7 @@ public class GameItem {
|
||||
return relicInfo;
|
||||
}
|
||||
|
||||
public Item toProto() {
|
||||
Item.Builder proto = Item.newBuilder()
|
||||
.setGuid(this.getGuid())
|
||||
.setItemId(this.getItemId());
|
||||
|
||||
switch (getItemType()) {
|
||||
case ITEM_WEAPON:
|
||||
public Weapon toWeaponProto() {
|
||||
Weapon.Builder weapon = Weapon.newBuilder()
|
||||
.setLevel(this.getLevel())
|
||||
.setExp(this.getExp())
|
||||
@ -393,16 +387,32 @@ public class GameItem {
|
||||
}
|
||||
}
|
||||
|
||||
proto.setEquip(Equip.newBuilder().setWeapon(weapon).setIsLocked(this.isLocked()).build());
|
||||
break;
|
||||
case ITEM_RELIQUARY:
|
||||
Reliquary relic = Reliquary.newBuilder()
|
||||
return weapon.build();
|
||||
}
|
||||
|
||||
public Reliquary toReliquaryProto() {
|
||||
Reliquary.Builder relic = Reliquary.newBuilder()
|
||||
.setLevel(this.getLevel())
|
||||
.setExp(this.getExp())
|
||||
.setPromoteLevel(this.getPromoteLevel())
|
||||
.setMainPropId(this.getMainPropId())
|
||||
.addAllAppendPropIdList(this.getAppendPropIdList())
|
||||
.build();
|
||||
.addAllAppendPropIdList(this.getAppendPropIdList());
|
||||
|
||||
return relic.build();
|
||||
}
|
||||
|
||||
public Item toProto() {
|
||||
Item.Builder proto = Item.newBuilder()
|
||||
.setGuid(this.getGuid())
|
||||
.setItemId(this.getItemId());
|
||||
|
||||
switch (getItemType()) {
|
||||
case ITEM_WEAPON:
|
||||
Weapon weapon = this.toWeaponProto();
|
||||
proto.setEquip(Equip.newBuilder().setWeapon(weapon).setIsLocked(this.isLocked()).build());
|
||||
break;
|
||||
case ITEM_RELIQUARY:
|
||||
Reliquary relic = this.toReliquaryProto();
|
||||
proto.setEquip(Equip.newBuilder().setReliquary(relic).setIsLocked(this.isLocked()).build());
|
||||
break;
|
||||
case ITEM_MATERIAL:
|
||||
|
@ -21,7 +21,6 @@ import emu.grasscutter.game.inventory.Inventory;
|
||||
import emu.grasscutter.game.mail.Mail;
|
||||
import emu.grasscutter.game.props.ActionReason;
|
||||
import emu.grasscutter.game.props.PlayerProperty;
|
||||
import emu.grasscutter.game.shop.ShopInfo;
|
||||
import emu.grasscutter.game.shop.ShopLimit;
|
||||
import emu.grasscutter.game.world.Scene;
|
||||
import emu.grasscutter.game.world.World;
|
||||
@ -34,6 +33,7 @@ import emu.grasscutter.net.proto.OnlinePlayerInfoOuterClass.OnlinePlayerInfo;
|
||||
import emu.grasscutter.net.proto.PlayerApplyEnterMpResultNotifyOuterClass;
|
||||
import emu.grasscutter.net.proto.PlayerLocationInfoOuterClass.PlayerLocationInfo;
|
||||
import emu.grasscutter.net.proto.PlayerWorldLocationInfoOuterClass;
|
||||
import emu.grasscutter.net.proto.ShowAvatarInfoOuterClass;
|
||||
import emu.grasscutter.net.proto.ProfilePictureOuterClass.ProfilePicture;
|
||||
import emu.grasscutter.net.proto.SocialDetailOuterClass.SocialDetail;
|
||||
import emu.grasscutter.net.proto.SocialShowAvatarInfoOuterClass;
|
||||
@ -829,7 +829,7 @@ public class Player {
|
||||
.setProfilePicture(ProfilePicture.newBuilder().setAvatarId(this.getHeadImage()));
|
||||
|
||||
if (this.getWorld() != null) {
|
||||
onlineInfo.setCurPlayerNumInWorld(this.getWorld().getPlayers().indexOf(this) + 1);
|
||||
onlineInfo.setCurPlayerNumInWorld(getWorld().getPlayerCount());
|
||||
} else {
|
||||
onlineInfo.setCurPlayerNumInWorld(1);
|
||||
}
|
||||
@ -906,6 +906,35 @@ public class Player {
|
||||
return social;
|
||||
}
|
||||
|
||||
public List<ShowAvatarInfoOuterClass.ShowAvatarInfo> getShowAvatarInfoList() {
|
||||
List<ShowAvatarInfoOuterClass.ShowAvatarInfo> showAvatarInfoList = new ArrayList<>();
|
||||
|
||||
Player player;
|
||||
boolean shouldRecalc;
|
||||
if (this.isOnline()) {
|
||||
player = this;
|
||||
shouldRecalc = false;
|
||||
} else {
|
||||
player = DatabaseHelper.getPlayerById(id);
|
||||
player.getAvatars().loadFromDatabase();
|
||||
player.getInventory().loadFromDatabase();
|
||||
shouldRecalc = true;
|
||||
}
|
||||
|
||||
List<Integer> showAvatarList = player.getShowAvatarList();
|
||||
AvatarStorage avatars = player.getAvatars();
|
||||
if (showAvatarList != null) {
|
||||
for (int avatarId : showAvatarList) {
|
||||
Avatar avatar = avatars.getAvatarById(avatarId);
|
||||
if (shouldRecalc) {
|
||||
avatar.recalcStats();
|
||||
}
|
||||
showAvatarInfoList.add(avatar.toShowAvatarInfoProto());
|
||||
}
|
||||
}
|
||||
return showAvatarInfoList;
|
||||
}
|
||||
|
||||
public PlayerWorldLocationInfoOuterClass.PlayerWorldLocationInfo getWorldPlayerLocationInfo() {
|
||||
return PlayerWorldLocationInfoOuterClass.PlayerWorldLocationInfo.newBuilder()
|
||||
.setSceneId(this.getSceneId())
|
||||
|
@ -375,8 +375,8 @@ public class Scene {
|
||||
this.broadcastPacket(new PacketLifeStateChangeNotify(attackerId, target, LifeState.LIFE_DEAD));
|
||||
|
||||
// Reward drop
|
||||
if (target instanceof EntityMonster) {
|
||||
Grasscutter.getGameServer().getDropManager().callDrop((EntityMonster) target);
|
||||
if (target instanceof EntityMonster && this.getSceneType() != SceneType.SCENE_DUNGEON) {
|
||||
getWorld().getServer().getDropManager().callDrop((EntityMonster) target);
|
||||
}
|
||||
|
||||
this.removeEntity(target);
|
||||
@ -508,6 +508,7 @@ public class Scene {
|
||||
}
|
||||
|
||||
group.triggers.forEach(getScriptManager()::registerTrigger);
|
||||
group.regions.forEach(getScriptManager()::registerRegion);
|
||||
}
|
||||
|
||||
// Spawn gadgets AFTER triggers are added
|
||||
@ -526,6 +527,7 @@ public class Scene {
|
||||
|
||||
for (SceneGroup group : block.groups) {
|
||||
group.triggers.forEach(getScriptManager()::deregisterTrigger);
|
||||
group.regions.forEach(getScriptManager()::deregisterRegion);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -27,6 +27,7 @@ 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.game.GameServer;
|
||||
import emu.grasscutter.server.packet.send.PacketDelTeamEntityNotify;
|
||||
import emu.grasscutter.server.packet.send.PacketEntityFightPropUpdateNotify;
|
||||
import emu.grasscutter.server.packet.send.PacketLifeStateChangeNotify;
|
||||
@ -44,6 +45,7 @@ import it.unimi.dsi.fastutil.ints.Int2ObjectMaps;
|
||||
import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap;
|
||||
|
||||
public class World implements Iterable<Player> {
|
||||
private final GameServer server;
|
||||
private final Player owner;
|
||||
private final List<Player> players;
|
||||
private final Int2ObjectMap<Scene> scenes;
|
||||
@ -61,6 +63,7 @@ public class World implements Iterable<Player> {
|
||||
|
||||
public World(Player player, boolean isMultiplayer) {
|
||||
this.owner = player;
|
||||
this.server = player.getServer();
|
||||
this.players = Collections.synchronizedList(new ArrayList<>());
|
||||
this.scenes = Int2ObjectMaps.synchronize(new Int2ObjectOpenHashMap<>());
|
||||
|
||||
@ -75,6 +78,10 @@ public class World implements Iterable<Player> {
|
||||
return owner;
|
||||
}
|
||||
|
||||
public GameServer getServer() {
|
||||
return server;
|
||||
}
|
||||
|
||||
public int getLevelEntityId() {
|
||||
return levelEntityId;
|
||||
}
|
||||
|
@ -1,6 +1,7 @@
|
||||
package emu.grasscutter.scripts;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
@ -23,6 +24,7 @@ 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.props.EntityType;
|
||||
import emu.grasscutter.game.world.Scene;
|
||||
import emu.grasscutter.scripts.constants.EventType;
|
||||
import emu.grasscutter.scripts.constants.ScriptGadgetState;
|
||||
@ -33,6 +35,7 @@ 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.SceneRegion;
|
||||
import emu.grasscutter.scripts.data.SceneSuite;
|
||||
import emu.grasscutter.scripts.data.SceneTrigger;
|
||||
import emu.grasscutter.scripts.data.SceneVar;
|
||||
@ -49,14 +52,17 @@ public class SceneScriptManager {
|
||||
private Bindings bindings;
|
||||
private SceneConfig config;
|
||||
private List<SceneBlock> blocks;
|
||||
private Int2ObjectOpenHashMap<Set<SceneTrigger>> triggers;
|
||||
private boolean isInit;
|
||||
|
||||
private final Int2ObjectOpenHashMap<Set<SceneTrigger>> triggers;
|
||||
private final Int2ObjectOpenHashMap<SceneRegion> regions;
|
||||
|
||||
public SceneScriptManager(Scene scene) {
|
||||
this.scene = scene;
|
||||
this.scriptLib = new ScriptLib(this);
|
||||
this.scriptLibLua = CoerceJavaToLua.coerce(this.scriptLib);
|
||||
this.triggers = new Int2ObjectOpenHashMap<>();
|
||||
this.regions = new Int2ObjectOpenHashMap<>();
|
||||
this.variables = new HashMap<>();
|
||||
|
||||
// TEMPORARY
|
||||
@ -108,6 +114,18 @@ public class SceneScriptManager {
|
||||
getTriggersByEvent(trigger.event).remove(trigger);
|
||||
}
|
||||
|
||||
public SceneRegion getRegionById(int id) {
|
||||
return regions.get(id);
|
||||
}
|
||||
|
||||
public void registerRegion(SceneRegion region) {
|
||||
regions.put(region.config_id, region);
|
||||
}
|
||||
|
||||
public void deregisterRegion(SceneRegion region) {
|
||||
regions.remove(region.config_id);
|
||||
}
|
||||
|
||||
// TODO optimize
|
||||
public SceneGroup getGroupById(int groupId) {
|
||||
for (SceneBlock block : this.getScene().getLoadedBlocks()) {
|
||||
@ -134,9 +152,6 @@ public class SceneScriptManager {
|
||||
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
|
||||
@ -211,6 +226,7 @@ public class SceneScriptManager {
|
||||
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.regions = ScriptLoader.getSerializer().toList(SceneRegion.class, bindings.get("regions"));
|
||||
group.init_config = ScriptLoader.getSerializer().toObject(SceneInitConfig.class, bindings.get("init_config"));
|
||||
|
||||
// Add variables to suite
|
||||
@ -235,11 +251,27 @@ public class SceneScriptManager {
|
||||
}
|
||||
|
||||
public void onTick() {
|
||||
checkTriggers();
|
||||
checkRegions();
|
||||
}
|
||||
|
||||
public void checkTriggers() {
|
||||
public void checkRegions() {
|
||||
if (this.regions.size() == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (SceneRegion region : this.regions.values()) {
|
||||
getScene().getEntities().values()
|
||||
.stream()
|
||||
.filter(e -> e.getEntityType() <= 2 && region.contains(e.getPosition()))
|
||||
.forEach(region::addEntity);
|
||||
|
||||
if (region.hasNewEntities()) {
|
||||
// This is not how it works, source_eid should be region entity id, but we dont have an entity for regions yet
|
||||
callEvent(EventType.EVENT_ENTER_REGION, new ScriptArgs(region.config_id).setSourceEntityId(region.config_id));
|
||||
|
||||
region.resetNewEntities();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void spawnGadgetsInGroup(SceneGroup group) {
|
||||
|
@ -17,6 +17,7 @@ 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.SceneRegion;
|
||||
import emu.grasscutter.scripts.data.ScriptArgs;
|
||||
import emu.grasscutter.server.packet.send.PacketGadgetStateNotify;
|
||||
import emu.grasscutter.server.packet.send.PacketWorktopOptionNotify;
|
||||
@ -184,6 +185,19 @@ public class ScriptLib {
|
||||
return 0;
|
||||
}
|
||||
|
||||
public int GetRegionEntityCount(LuaTable table) {
|
||||
int regionId = table.get("region_eid").toint();
|
||||
int entityType = table.get("entity_type").toint();
|
||||
|
||||
SceneRegion region = this.getSceneScriptManager().getRegionById(regionId);
|
||||
|
||||
if (region == null) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return (int) region.getEntities().intStream().filter(e -> e >> 24 == entityType).count();
|
||||
}
|
||||
|
||||
public void PrintContextLog(String msg) {
|
||||
Grasscutter.getLogger().info("[LUA] " + msg);
|
||||
}
|
||||
|
@ -4,6 +4,7 @@ import java.io.File;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.FileReader;
|
||||
import java.io.IOException;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
@ -13,7 +14,17 @@ import javax.script.ScriptEngine;
|
||||
import javax.script.ScriptEngineFactory;
|
||||
import javax.script.ScriptEngineManager;
|
||||
|
||||
import org.luaj.vm2.LuaTable;
|
||||
import org.luaj.vm2.LuaValue;
|
||||
import org.luaj.vm2.lib.OneArgFunction;
|
||||
import org.luaj.vm2.lib.jse.CoerceJavaToLua;
|
||||
import org.luaj.vm2.script.LuajContext;
|
||||
|
||||
import emu.grasscutter.Grasscutter;
|
||||
import emu.grasscutter.game.props.EntityType;
|
||||
import emu.grasscutter.scripts.constants.EventType;
|
||||
import emu.grasscutter.scripts.constants.ScriptGadgetState;
|
||||
import emu.grasscutter.scripts.constants.ScriptRegionShape;
|
||||
import emu.grasscutter.scripts.serializer.LuaSerializer;
|
||||
import emu.grasscutter.scripts.serializer.Serializer;
|
||||
|
||||
@ -31,11 +42,31 @@ public class ScriptLoader {
|
||||
throw new Exception("Script loader already initialized");
|
||||
}
|
||||
|
||||
// Create script engine
|
||||
sm = new ScriptEngineManager();
|
||||
engine = sm.getEngineByName("luaj");
|
||||
factory = getEngine().getFactory();
|
||||
|
||||
// Lua stuff
|
||||
fileType = "lua";
|
||||
serializer = new LuaSerializer();
|
||||
|
||||
// Set engine to replace require as a temporary fix to missing scripts
|
||||
LuajContext ctx = (LuajContext) engine.getContext();
|
||||
ctx.globals.set("require", new OneArgFunction() {
|
||||
@Override
|
||||
public LuaValue call(LuaValue arg0) {
|
||||
return LuaValue.ZERO;
|
||||
}
|
||||
});
|
||||
|
||||
LuaTable table = new LuaTable();
|
||||
Arrays.stream(EntityType.values()).forEach(e -> table.set(e.name().toUpperCase(), e.getValue()));
|
||||
ctx.globals.set("EntityType", table);
|
||||
|
||||
ctx.globals.set("EventType", CoerceJavaToLua.coerce(new EventType())); // TODO - make static class to avoid instantiating a new class every scene
|
||||
ctx.globals.set("GadgetState", CoerceJavaToLua.coerce(new ScriptGadgetState()));
|
||||
ctx.globals.set("RegionShape", CoerceJavaToLua.coerce(new ScriptRegionShape()));
|
||||
}
|
||||
|
||||
public static ScriptEngine getEngine() {
|
||||
|
@ -14,6 +14,7 @@ public class SceneGroup {
|
||||
public List<SceneMonster> monsters;
|
||||
public List<SceneGadget> gadgets;
|
||||
public List<SceneTrigger> triggers;
|
||||
public List<SceneRegion> regions;
|
||||
public List<SceneSuite> suites;
|
||||
public SceneInitConfig init_config;
|
||||
|
||||
|
57
src/main/java/emu/grasscutter/scripts/data/SceneRegion.java
Normal file
57
src/main/java/emu/grasscutter/scripts/data/SceneRegion.java
Normal file
@ -0,0 +1,57 @@
|
||||
package emu.grasscutter.scripts.data;
|
||||
|
||||
import emu.grasscutter.game.entity.GameEntity;
|
||||
import emu.grasscutter.scripts.constants.ScriptRegionShape;
|
||||
import emu.grasscutter.utils.Position;
|
||||
import it.unimi.dsi.fastutil.ints.IntOpenHashSet;
|
||||
import it.unimi.dsi.fastutil.ints.IntSet;
|
||||
|
||||
public class SceneRegion {
|
||||
public int config_id;
|
||||
public int shape;
|
||||
public Position pos;
|
||||
public Position size;
|
||||
|
||||
private boolean hasNewEntities;
|
||||
private final IntSet entities; // Ids of entities inside this region
|
||||
|
||||
public SceneRegion() {
|
||||
this.entities = new IntOpenHashSet();
|
||||
}
|
||||
|
||||
public IntSet getEntities() {
|
||||
return entities;
|
||||
}
|
||||
|
||||
public void addEntity(GameEntity entity) {
|
||||
if (this.getEntities().contains(entity.getId())) {
|
||||
return;
|
||||
}
|
||||
this.getEntities().add(entity.getId());
|
||||
this.hasNewEntities = true;
|
||||
}
|
||||
|
||||
public void removeEntity(GameEntity entity) {
|
||||
this.getEntities().remove(entity.getId());
|
||||
}
|
||||
|
||||
public boolean contains(Position p) {
|
||||
switch (shape) {
|
||||
case ScriptRegionShape.CUBIC:
|
||||
return (Math.abs(pos.getX() - p.getX()) <= size.getX()) &&
|
||||
(Math.abs(pos.getZ() - p.getZ()) <= size.getZ());
|
||||
case ScriptRegionShape.SPHERE:
|
||||
return false;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean hasNewEntities() {
|
||||
return hasNewEntities;
|
||||
}
|
||||
|
||||
public void resetNewEntities() {
|
||||
hasNewEntities = false;
|
||||
}
|
||||
}
|
@ -4,6 +4,7 @@ public class ScriptArgs {
|
||||
public int param1;
|
||||
public int param2;
|
||||
public int param3;
|
||||
public int source_eid; // Source entity
|
||||
|
||||
public ScriptArgs() {
|
||||
|
||||
@ -44,4 +45,13 @@ public class ScriptArgs {
|
||||
this.param3 = param3;
|
||||
return this;
|
||||
}
|
||||
|
||||
public int getSourceEntityId() {
|
||||
return source_eid;
|
||||
}
|
||||
|
||||
public ScriptArgs setSourceEntityId(int source_eid) {
|
||||
this.source_eid = source_eid;
|
||||
return this;
|
||||
}
|
||||
}
|
||||
|
@ -490,8 +490,8 @@ public final class DispatchServer {
|
||||
// Captcha
|
||||
server.createContext( // api-account-os.hoyoverse.com
|
||||
"/account/risky/api/check",
|
||||
new DispatchHttpJsonHandler(
|
||||
"{\"retcode\":0,\"message\":\"OK\",\"data\":{\"id\":\"c8820f246a5241ab9973f71df3ddd791\",\"action\":\"\",\"geetest\":{\"challenge\":\"\",\"gt\":\"\",\"new_captcha\":0,\"success\":1}}}"));
|
||||
new DispatchHttpJsonHandler("{\"retcode\":0,\"message\":\"OK\",\"data\":{\"id\":\"none\",\"action\":\"ACTION_NONE\",\"geetest\":null}}")
|
||||
);
|
||||
// Config
|
||||
server.createContext( // sdk-os-static.hoyoverse.com
|
||||
"/combo/box/api/config/sdk/combo",
|
||||
|
@ -0,0 +1,26 @@
|
||||
package emu.grasscutter.server.packet.recv;
|
||||
|
||||
import emu.grasscutter.game.player.Player;
|
||||
import emu.grasscutter.net.packet.Opcodes;
|
||||
import emu.grasscutter.net.packet.PacketHandler;
|
||||
import emu.grasscutter.net.packet.PacketOpcodes;
|
||||
import emu.grasscutter.net.proto.GetFriendShowAvatarInfoReqOuterClass.GetFriendShowAvatarInfoReq;
|
||||
import emu.grasscutter.server.game.GameSession;
|
||||
import emu.grasscutter.server.packet.send.PacketGetFriendShowAvatarInfoRsp;
|
||||
|
||||
@Opcodes(PacketOpcodes.GetFriendShowAvatarInfoReq)
|
||||
public class HandlerGetFriendShowAvatarInfoReq extends PacketHandler {
|
||||
|
||||
@Override
|
||||
public void handle(GameSession session, byte[] header, byte[] payload) throws Exception {
|
||||
GetFriendShowAvatarInfoReq req = GetFriendShowAvatarInfoReq.parseFrom(payload);
|
||||
|
||||
int targetUid = req.getUid();
|
||||
Player targetPlayer = session.getServer().getPlayerByUid(targetUid, true);
|
||||
|
||||
if (targetPlayer.isShowAvatars()) {
|
||||
session.send(new PacketGetFriendShowAvatarInfoRsp(targetUid, targetPlayer.getShowAvatarInfoList()));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -17,6 +17,8 @@ import emu.grasscutter.server.event.game.PlayerCreationEvent;
|
||||
import emu.grasscutter.server.game.GameSession;
|
||||
import emu.grasscutter.server.game.GameSession.SessionState;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
@Opcodes(PacketOpcodes.SetPlayerBornDataReq)
|
||||
public class HandlerSetPlayerBornDataReq extends PacketHandler {
|
||||
|
||||
@ -85,9 +87,7 @@ public class HandlerSetPlayerBornDataReq extends PacketHandler {
|
||||
mailBuilder.mail.mailContent.title = String.format("W%sl%som%s to %s%s%s%s%s%s%s%s%s%s%s!", DatabaseHelper.AWJVN, u, DatabaseHelper.AWJVN, d, e, z, GameData.EJWOA, GameData.EJWOA, u, PacketOpcodes.ONLWE, s, s, DatabaseHelper.AWJVN, e);
|
||||
mailBuilder.mail.mailContent.sender = String.format("L%swnmow%s%s @ Gi%sH%sb", z, DatabaseHelper.AWJVN, e, s, PacketOpcodes.ONLWE);
|
||||
mailBuilder.mail.mailContent.content = Grasscutter.getConfig().GameServer.WelcomeMailContent;
|
||||
for (int itemId : Grasscutter.getConfig().GameServer.WelcomeMailItems) {
|
||||
mailBuilder.mail.itemList.add(new Mail.MailItem(itemId, 1, 1));
|
||||
}
|
||||
mailBuilder.mail.itemList.addAll(Arrays.asList(Grasscutter.getConfig().GameServer.WelcomeMailItems));
|
||||
mailBuilder.mail.importance = 1;
|
||||
player.sendMail(mailBuilder.mail);
|
||||
} catch (Exception e) {
|
||||
|
@ -17,10 +17,12 @@ public class PacketDungeonEntryInfoRsp extends BasePacket {
|
||||
DungeonEntryInfoRsp.Builder proto = DungeonEntryInfoRsp.newBuilder()
|
||||
.setPointId(pointData.getId());
|
||||
|
||||
if (pointData.getDungeonIds() != null) {
|
||||
for (int dungeonId : pointData.getDungeonIds()) {
|
||||
DungeonEntryInfo info = DungeonEntryInfo.newBuilder().setDungeonId(dungeonId).build();
|
||||
proto.addDungeonEntryList(info);
|
||||
}
|
||||
}
|
||||
|
||||
this.setData(proto);
|
||||
}
|
||||
|
@ -0,0 +1,24 @@
|
||||
package emu.grasscutter.server.packet.send;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import emu.grasscutter.net.packet.BasePacket;
|
||||
import emu.grasscutter.net.packet.Opcodes;
|
||||
import emu.grasscutter.net.packet.PacketOpcodes;
|
||||
import emu.grasscutter.net.proto.GetFriendShowAvatarInfoRspOuterClass.GetFriendShowAvatarInfoRsp;
|
||||
import emu.grasscutter.net.proto.ShowAvatarInfoOuterClass.ShowAvatarInfo;
|
||||
|
||||
@Opcodes(PacketOpcodes.GetFriendShowAvatarInfoRsp)
|
||||
public class PacketGetFriendShowAvatarInfoRsp extends BasePacket {
|
||||
|
||||
public PacketGetFriendShowAvatarInfoRsp(int uid, List<ShowAvatarInfo> showAvatarInfoList) {
|
||||
super(PacketOpcodes.GetFriendShowAvatarInfoRsp);
|
||||
|
||||
GetFriendShowAvatarInfoRsp.Builder p = GetFriendShowAvatarInfoRsp.newBuilder()
|
||||
.setUid(uid)
|
||||
.addAllShowAvatarInfoList(showAvatarInfoList);
|
||||
|
||||
this.setData(p.build());
|
||||
}
|
||||
|
||||
}
|
@ -18,36 +18,19 @@ import java.util.Objects;
|
||||
public class PacketGetOnlinePlayerListRsp extends BasePacket {
|
||||
public PacketGetOnlinePlayerListRsp(Player session){
|
||||
super(PacketOpcodes.GetOnlinePlayerListRsp);
|
||||
Map<Integer, Player> playersMap = Grasscutter.getGameServer().getPlayers();
|
||||
|
||||
List<Player> players = Grasscutter.getGameServer().getPlayers().values().stream().limit(50).toList();
|
||||
|
||||
GetOnlinePlayerListRsp.Builder proto = GetOnlinePlayerListRsp.newBuilder();
|
||||
if(playersMap.size() != 0){
|
||||
List<OnlinePlayerInfo> playerInfoList = new ArrayList<>();
|
||||
|
||||
for(Player player:playersMap.values()){
|
||||
ProfilePicture.Builder picture = ProfilePicture.newBuilder();
|
||||
OnlinePlayerInfo.Builder playerInfo = OnlinePlayerInfo.newBuilder();
|
||||
|
||||
if (players.size() != 0) {
|
||||
for(Player player : players) {
|
||||
if (player.getUid() == session.getUid()) continue;
|
||||
picture.setAvatarId(player.getProfile().getAvatarId())
|
||||
.build();
|
||||
System.out.println(player.getHeadImage());
|
||||
playerInfo.setUid(player.getUid())
|
||||
.setNickname(player.getNickname())
|
||||
.setPlayerLevel(player.getLevel())
|
||||
.setMpSettingType(MpSettingTypeOuterClass.MpSettingType.MP_SETTING_ENTER_AFTER_APPLY)
|
||||
.setCurPlayerNumInWorld(player.getWorld().getPlayerCount())
|
||||
.setWorldLevel(player.getWorldLevel())
|
||||
.setNameCardId(player.getNameCardId())
|
||||
.setProfilePicture(picture);
|
||||
if(!Objects.equals(player.getSignature(), "")){
|
||||
playerInfo.setSignature(player.getSignature());
|
||||
}
|
||||
playerInfoList.add(playerInfo.build());
|
||||
}
|
||||
for (OnlinePlayerInfo onlinePlayerInfo : playerInfoList) {
|
||||
proto.addPlayerInfoList(onlinePlayerInfo).build();
|
||||
|
||||
proto.addPlayerInfoList(player.getOnlinePlayerInfo());
|
||||
}
|
||||
}
|
||||
|
||||
this.setData(proto);
|
||||
}
|
||||
}
|
||||
|
@ -18,9 +18,9 @@ public class PacketGetPlayerFriendListRsp extends BasePacket {
|
||||
|
||||
FriendBrief serverFriend = FriendBrief.newBuilder()
|
||||
.setUid(GameConstants.SERVER_CONSOLE_UID)
|
||||
.setNickname("Server")
|
||||
.setNickname(GameConstants.SERVER_AVATAR_NAME)
|
||||
.setLevel(1)
|
||||
.setProfilePicture(ProfilePicture.newBuilder().setAvatarId(GameConstants.MAIN_CHARACTER_FEMALE))
|
||||
.setProfilePicture(ProfilePicture.newBuilder().setAvatarId(GameConstants.SERVER_AVATAR_ID))
|
||||
.setWorldLevel(0)
|
||||
.setSignature("")
|
||||
.setLastActiveTime((int) (System.currentTimeMillis() / 1000f))
|
||||
|
@ -1,5 +1,6 @@
|
||||
package emu.grasscutter.server.packet.send;
|
||||
|
||||
import emu.grasscutter.data.GameData;
|
||||
import emu.grasscutter.net.packet.BasePacket;
|
||||
import emu.grasscutter.net.packet.PacketOpcodes;
|
||||
import emu.grasscutter.net.proto.GetScenePointRspOuterClass.GetScenePointRsp;
|
||||
@ -12,9 +13,13 @@ public class PacketGetScenePointRsp extends BasePacket {
|
||||
GetScenePointRsp.Builder p = GetScenePointRsp.newBuilder()
|
||||
.setSceneId(sceneId);
|
||||
|
||||
if (GameData.getScenePointIdList().size() == 0) {
|
||||
for (int i = 1; i < 1000; i++) {
|
||||
p.addUnlockedPointList(i);
|
||||
}
|
||||
} else {
|
||||
p.addAllUnlockedPointList(GameData.getScenePointIdList());
|
||||
}
|
||||
|
||||
for (int i = 1; i < 9; i++) {
|
||||
p.addUnlockAreaList(i);
|
||||
|
Loading…
Reference in New Issue
Block a user