Commit c25e809f authored by Benjamin Elsdon's avatar Benjamin Elsdon
Browse files

Merge remote-tracking branch 'upstream/development' into dev-mail

parents 9e7c9f46 b6d8dd0d
...@@ -3,9 +3,14 @@ on: ...@@ -3,9 +3,14 @@ on:
push: push:
branches: branches:
- "stable" - "stable"
pull_request:
types:
- opened
- synchronize
- reopened
jobs: jobs:
Build-Server-Jar: Build-Server-Jar:
runs-on: windows-latest runs-on: ubuntu-latest
steps: steps:
- name: Checkout - name: Checkout
uses: actions/checkout@v2 uses: actions/checkout@v2
...@@ -13,12 +18,11 @@ jobs: ...@@ -13,12 +18,11 @@ jobs:
uses: actions/setup-java@v3 uses: actions/setup-java@v3
with: with:
distribution: temurin distribution: temurin
java-version: '8' java-version: '16'
- name: Run Gradle - name: Run Gradle
run: .\gradlew.bat && .\gradlew jar run: ./gradlew && ./gradlew jar
- name: Upload build - name: Upload build
uses: actions/upload-artifact@v3 uses: actions/upload-artifact@v3
with: with:
name: Grasscutter name: Grasscutter
path: grasscutter.jar path: grasscutter.jar
...@@ -50,8 +50,7 @@ resources/* ...@@ -50,8 +50,7 @@ resources/*
logs/* logs/*
data/AbilityEmbryos.json data/AbilityEmbryos.json
data/OpenConfig.json data/OpenConfig.json
proto/auto/ proto/*
proto/protoc.exe
GM Handbook.txt GM Handbook.txt
config.json config.json
mitmdump.exe mitmdump.exe
......
...@@ -10,10 +10,10 @@ A WIP server reimplementation for *some anime game* 2.3-2.6 ...@@ -10,10 +10,10 @@ A WIP server reimplementation for *some anime game* 2.3-2.6
* Inventory features (recieving items/characters, upgrading items/characters, etc) * Inventory features (recieving items/characters, upgrading items/characters, etc)
* Gacha system * Gacha system
* Friends list * Friends list
* Co-op *partially* work * Co-op *partially* works
# Quick setup guide # Quick setup guide
### Note ### Note
* If you update from an older version, delete `config.json` for regeneration * If you updated from an older version, delete `config.json` to regenerate it.
### Prerequisites ### Prerequisites
* Java 16 * Java 16
...@@ -21,15 +21,15 @@ A WIP server reimplementation for *some anime game* 2.3-2.6 ...@@ -21,15 +21,15 @@ A WIP server reimplementation for *some anime game* 2.3-2.6
* Proxy daemon: mitmproxy (mitmdump, recommended), Fiddler Classic, etc. * Proxy daemon: mitmproxy (mitmdump, recommended), Fiddler Classic, etc.
### Starting up Grasscutter server (Assuming you are on Windows) ### Starting up Grasscutter server (Assuming you are on Windows)
1. Setup compile environment `gradlew.bat` 1. Setup the compile environment with `gradlew.bat`
2. Compile Grasscutter with `gradlew jar` 2. Compile Grasscutter with `gradlew jar`
3. Create a folder named `resources` in your Grasscutter directory, bring your `BinOutput` and `ExcelBinOutput` folders into it *(Check the wiki for more details how to get those.)* 3. Create a folder named `resources` in your Grasscutter directory, move your `BinOutput` and `ExcelBinOutput` folders there *(Check the wiki for more details on how to get those.)*
4. Run Grasscutter with `java -jar grasscutter.jar`. Make sure mongodb service is running as well. 4. Run Grasscutter with `java -jar grasscutter.jar`. Make sure mongodb service is running as well.
### Connecting with the client ### Connecting with the client
½. Create an account using *server console command* below ½. Create an account using *server console command* below
1. Run a proxy daemon: (choose either one) 1. Run a proxy daemon: (choose either one)
- mitmdump: `mitmdump -s proxy.py -k` - mitmdump: `mitmdump -s proxy.py -k --allow-hosts ".*\.yuanshen\.com|.*\.mihoyo\.com|.*\.hoyoverse\.com"`
- Fiddler Classic: Run Fiddler Classic, turn on `Decrypt https traffic` in setting and change the default port there (Tools -> Options -> Connections) to anything other than `8888`, and load [this script](https://github.lunatic.moe/fiddlerscript). - Fiddler Classic: Run Fiddler Classic, turn on `Decrypt https traffic` in setting and change the default port there (Tools -> Options -> Connections) to anything other than `8888`, and load [this script](https://github.lunatic.moe/fiddlerscript).
- [Hosts file](https://github.com/Melledy/Grasscutter/wiki/Running#traffic-route-map) - [Hosts file](https://github.com/Melledy/Grasscutter/wiki/Running#traffic-route-map)
2. Trust CA certificate: 2. Trust CA certificate:
...@@ -46,7 +46,7 @@ There is a dummy user named "Server" in every player's friends list that you can ...@@ -46,7 +46,7 @@ There is a dummy user named "Server" in every player's friends list that you can
`spawn [monster id] [level] [amount]` `spawn [monster id] [level] [amount]`
`give [item id] [amount]` `give [item id] [amount] [level]`
`givechar [avatar id] [level]` `givechar [avatar id] [level]`
...@@ -54,26 +54,26 @@ There is a dummy user named "Server" in every player's friends list that you can ...@@ -54,26 +54,26 @@ There is a dummy user named "Server" in every player's friends list that you can
`killall` `killall`
`setworldlevel [level]` - Relog to see effects properly `setworldlevel [level]` - Changes your world level, relog to see effects properly
`godmode` - Prevents you from taking damage `godmode` - Prevents you from taking damage
`resetconst` - Resets the constellation level on your current active character, will need to relog after using the command to see any changes. `resetconst` - Resets the constellation level on your currently selected character, will need to relog after using the command to see any changes.
`setstats [stats] [amount]` - Changes the current character's specified stat. `setstats [stats] [amount]` - Changes the currently selected character's specified stat.
`clearartifacts` - Deletes all unequipped and unlocked level 0 artifacts, **including yellow rarity ones** from your inventory `clearartifacts` - Deletes all unequipped and unlocked level 0 artifacts, **including 5-star rarity ones** from your inventory
`pos` - Gets your current coordinate. `pos` - Gets your current coordinates.
`weather [weather id] [climate id]` - Changes the current weather. `weather [weather id] [climate id]` - Changes the current weather.
*More commands will be updated in the [wiki](https://github.com/Melledy/Grasscutter/wiki/).* *More commands will be updated in the [wiki](https://github.com/Melledy/Grasscutter/wiki/).*
### Bonus ### Bonus
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. When you want to teleport somewhere, use the in-game marking function on the Map, click Confirm. You will see your character falling from a very high spot at the exact location you marked.
# Quick Troubleshooting # Quick Troubleshooting
* If compiling wasn't successful, please check your JDK installation (must be JDK 8 and validated JDK's bin PATH variable) * If compiling wasn't successful, please check your JDK installation (must be JDK 8 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 * My client doesn't connect, doesn't login, 4206, etc... - Mostly your proxy daemon setup is *the issue*, if you're using Fiddler make sure it's running on a port other than 8888
* Startup sequence: Mongodb > Grasscutter > Proxy daemon (mitmdump, fiddler, etc.) > Client * Startup sequence: Mongodb > Grasscutter > Proxy daemon (mitmdump, fiddler, etc.) > Client
File mode changed from 100644 to 100755
...@@ -13,16 +13,15 @@ import emu.grasscutter.server.packet.send.PacketItemAddHintNotify; ...@@ -13,16 +13,15 @@ import emu.grasscutter.server.packet.send.PacketItemAddHintNotify;
import java.util.LinkedList; import java.util.LinkedList;
import java.util.List; import java.util.List;
@Command(label = "give", usage = "give [player] <itemId|itemName> [amount]", @Command(label = "give", usage = "give [player] <itemId|itemName> [amount] [level]", description = "Gives an item to you or the specified player", aliases = {
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 { public final class GiveCommand implements CommandHandler {
@Override @Override
public void execute(GenshinPlayer sender, List<String> args) { public void execute(GenshinPlayer sender, List<String> args) {
int target, item, amount = 1; int target, item, lvl, amount = 1;
if (sender == null && args.size() < 2) { if (sender == null && args.size() < 2) {
CommandHandler.sendMessage(null, "Usage: give <player> <itemId|itemName> [amount]"); CommandHandler.sendMessage(null, "Usage: give <player> <itemId|itemName> [amount] [level]");
return; return;
} }
...@@ -34,6 +33,7 @@ public final class GiveCommand implements CommandHandler { ...@@ -34,6 +33,7 @@ public final class GiveCommand implements CommandHandler {
try { try {
item = Integer.parseInt(args.get(0)); item = Integer.parseInt(args.get(0));
target = sender.getUid(); target = sender.getUid();
lvl = 1;
} catch (NumberFormatException ignored) { } catch (NumberFormatException ignored) {
// TODO: Parse from item name using GM Handbook. // TODO: Parse from item name using GM Handbook.
CommandHandler.sendMessage(sender, "Invalid item id."); CommandHandler.sendMessage(sender, "Invalid item id.");
...@@ -43,6 +43,7 @@ public final class GiveCommand implements CommandHandler { ...@@ -43,6 +43,7 @@ public final class GiveCommand implements CommandHandler {
case 2: // <itemId|itemName> [amount] | [player] <itemId|itemName> case 2: // <itemId|itemName> [amount] | [player] <itemId|itemName>
try { try {
target = Integer.parseInt(args.get(0)); target = Integer.parseInt(args.get(0));
lvl = 1;
if (Grasscutter.getGameServer().getPlayerByUid(target) == null && sender != null) { if (Grasscutter.getGameServer().getPlayerByUid(target) == null && sender != null) {
target = sender.getUid(); target = sender.getUid();
...@@ -57,17 +58,39 @@ public final class GiveCommand implements CommandHandler { ...@@ -57,17 +58,39 @@ public final class GiveCommand implements CommandHandler {
return; return;
} }
break; break;
case 3: // [player] <itemId|itemName> [amount] case 3: // [player] <itemId|itemName> [amount] | <itemId|itemName> [amount] [level]
try { try {
target = Integer.parseInt(args.get(0)); target = Integer.parseInt(args.get(0));
if (Grasscutter.getGameServer().getPlayerByUid(target) == null) { if (Grasscutter.getGameServer().getPlayerByUid(target) == null && sender != null) {
CommandHandler.sendMessage(sender, "Invalid player ID."); target = sender.getUid();
item = Integer.parseInt(args.get(0));
amount = Integer.parseInt(args.get(1));
lvl = Integer.parseInt(args.get(2));
} else {
item = Integer.parseInt(args.get(1));
amount = Integer.parseInt(args.get(2));
lvl = 1;
}
} catch (NumberFormatException ignored) {
// TODO: Parse from item name using GM Handbook.
CommandHandler.sendMessage(sender, "Invalid item or player ID.");
return; return;
} }
break;
case 4: // [player] <itemId|itemName> [amount] [level]
try {
target = Integer.parseInt(args.get(0));
if (Grasscutter.getGameServer().getPlayerByUid(target) == null) {
CommandHandler.sendMessage(sender, "Invalid player ID.");
return;
} else {
item = Integer.parseInt(args.get(1)); item = Integer.parseInt(args.get(1));
amount = Integer.parseInt(args.get(2)); amount = Integer.parseInt(args.get(2));
lvl = Integer.parseInt(args.get(3));
}
} catch (NumberFormatException ignored) { } catch (NumberFormatException ignored) {
// TODO: Parse from item name using GM Handbook. // TODO: Parse from item name using GM Handbook.
CommandHandler.sendMessage(sender, "Invalid item or player ID."); CommandHandler.sendMessage(sender, "Invalid item or player ID.");
...@@ -89,16 +112,37 @@ public final class GiveCommand implements CommandHandler { ...@@ -89,16 +112,37 @@ public final class GiveCommand implements CommandHandler {
return; return;
} }
this.item(targetPlayer, itemData, amount); this.item(targetPlayer, itemData, amount, lvl);
if (!itemData.isEquip())
CommandHandler.sendMessage(sender, String.format("Given %s of %s to %s.", amount, item, target)); CommandHandler.sendMessage(sender, String.format("Given %s of %s to %s.", amount, item, target));
else
CommandHandler.sendMessage(sender,
String.format("Given %s with level %s %s times to %s", item, lvl, amount, target));
} }
private void item(GenshinPlayer player, ItemData itemData, int amount) { private void item(GenshinPlayer player, ItemData itemData, int amount, int lvl) {
if (itemData.isEquip()) { if (itemData.isEquip()) {
List<GenshinItem> items = new LinkedList<>(); List<GenshinItem> items = new LinkedList<>();
for (int i = 0; i < amount; i++) { for (int i = 0; i < amount; i++) {
items.add(new GenshinItem(itemData)); GenshinItem item = new GenshinItem(itemData);
item.setCount(amount);
item.setLevel(lvl);
item.setPromoteLevel(0);
if (lvl > 20) { // 20/40
item.setPromoteLevel(1);
} else if (lvl > 40) { // 40/50
item.setPromoteLevel(2);
} else if (lvl > 50) { // 50/60
item.setPromoteLevel(3);
} else if (lvl > 60) { // 60/70
item.setPromoteLevel(4);
} else if (lvl > 70) { // 70/80
item.setPromoteLevel(5);
} else if (lvl > 80) { // 80/90
item.setPromoteLevel(6);
}
items.add(item);
} }
player.getInventory().addItems(items); player.getInventory().addItems(items);
player.sendPacket(new PacketItemAddHintNotify(items, ActionReason.SubfieldDrop)); player.sendPacket(new PacketItemAddHintNotify(items, ActionReason.SubfieldDrop));
...@@ -110,4 +154,3 @@ public final class GiveCommand implements CommandHandler { ...@@ -110,4 +154,3 @@ public final class GiveCommand implements CommandHandler {
} }
} }
} }
package emu.grasscutter.command.commands; package emu.grasscutter.command.commands;
import emu.grasscutter.Grasscutter;
import emu.grasscutter.command.Command; import emu.grasscutter.command.Command;
import emu.grasscutter.command.CommandHandler; import emu.grasscutter.command.CommandHandler;
import emu.grasscutter.game.GenshinPlayer; import emu.grasscutter.game.GenshinPlayer;
...@@ -16,7 +17,29 @@ public final class GodModeCommand implements CommandHandler { ...@@ -16,7 +17,29 @@ public final class GodModeCommand implements CommandHandler {
CommandHandler.sendMessage(null, "Run this command in-game."); CommandHandler.sendMessage(null, "Run this command in-game.");
return; // TODO: toggle player's godmode statue from console or other players return; // TODO: toggle player's godmode statue from console or other players
} }
sender.setGodmode(!sender.inGodmode());
sender.dropMessage("Godmode is now " + (sender.inGodmode() ? "enabled" : "disabled") + "."); int target;
if (args.size() == 1) {
try {
target = Integer.parseInt(args.get(0));
if (Grasscutter.getGameServer().getPlayerByUid(target) == null) {
target = sender.getUid();
}
} catch (NumberFormatException e) {
CommandHandler.sendMessage(sender, "Invalid player id.");
return;
}
} else {
target = sender.getUid();
}
GenshinPlayer targetPlayer = Grasscutter.getGameServer().getPlayerByUid(target);
if (targetPlayer == null) {
CommandHandler.sendMessage(sender, "Player not found.");
return;
}
targetPlayer.setGodmode(!targetPlayer.inGodmode());
sender.dropMessage("Godmode is now " + (targetPlayer.inGodmode() ? "enabled" : "disabled") +
"for " + targetPlayer.getNickname() + " .");
} }
} }
...@@ -17,6 +17,7 @@ public final class PositionCommand implements CommandHandler { ...@@ -17,6 +17,7 @@ public final class PositionCommand implements CommandHandler {
return; return;
} }
sender.dropMessage(String.format("Coord: %.3f, %.3f, %.3f", sender.getPos().getX(), sender.getPos().getY(), sender.getPos().getZ())); sender.dropMessage(String.format("Coord: %.3f, %.3f, %.3f\nScene id: %d",
sender.getPos().getX(), sender.getPos().getY(), sender.getPos().getZ(), sender.getSceneId()));
} }
} }
package emu.grasscutter.command.commands;
import java.util.List;
import emu.grasscutter.command.Command;
import emu.grasscutter.command.CommandHandler;
import emu.grasscutter.data.GenshinData;
import emu.grasscutter.game.GenshinPlayer;
import emu.grasscutter.game.avatar.GenshinAvatar;
import emu.grasscutter.server.packet.send.PacketAvatarFetterDataNotify;
@Command(label = "setfetterlevel", usage = "setfetterlevel <level>",
description = "Sets your fetter level for your current active character",
aliases = {"setfetterlvl"}, permission = "player.setfetterlevel")
public final class SetFetterLevelCommand implements CommandHandler {
@Override
public void execute(GenshinPlayer sender, List<String> args) {
if (sender == null) {
CommandHandler.sendMessage(null, "Run this command in-game.");
return;
}
if (args.size() < 1) {
CommandHandler.sendMessage(sender, "Usage: setfetterlevel <level>");
return;
}
try {
int fetterLevel = Integer.parseInt(args.get(0));
if (fetterLevel < 0 || fetterLevel > 10) {
CommandHandler.sendMessage(sender, "Fetter level must be between 0 and 10.");
return;
}
GenshinAvatar avatar = sender.getTeamManager().getCurrentAvatarEntity().getAvatar();
avatar.setFetterLevel(fetterLevel);
avatar.setFetterExp(GenshinData.getAvatarFetterLevelDataMap().get(fetterLevel).getExp());
avatar.save();
sender.sendPacket(new PacketAvatarFetterDataNotify(avatar));
CommandHandler.sendMessage(sender, "Fetter level set to " + fetterLevel);
} catch (NumberFormatException ignored) {
CommandHandler.sendMessage(null, "Invalid fetter level.");
}
}
}
package emu.grasscutter.command.commands;
import emu.grasscutter.command.Command;
import emu.grasscutter.command.CommandHandler;
import emu.grasscutter.game.GenshinPlayer;
import emu.grasscutter.utils.Position;
import java.util.List;
@Command(label = "teleport", usage = "teleport <x> <y> <z>", aliases = {"tp"},
description = "Change the player's position.", permission = "player.teleport")
public class TelePortCommand implements CommandHandler {
@Override
public void execute(GenshinPlayer sender, List<String> args) {
if (sender == null) {
CommandHandler.sendMessage(null, "Run this command in-game.");
return;
}
if (args.size() < 3){
CommandHandler.sendMessage(sender, "Usage: /tp <x> <y> <z> [scene id]");
return;
}
try {
float x = 0f;
float y = 0f;
float z = 0f;
if (args.get(0).contains("~")) {
if (args.get(0).equals("~")) {
x = sender.getPos().getX();
} else {
x = Float.parseFloat(args.get(0).replace("~", "")) + sender.getPos().getX();
}
} else {
x = Float.parseFloat(args.get(0));
}
if (args.get(1).contains("~")) {
if (args.get(1).equals("~")) {
y = sender.getPos().getY();
} else {
y = Float.parseFloat(args.get(1).replace("~", "")) + sender.getPos().getY();
}
} else {
y = Float.parseFloat(args.get(1));
}
if (args.get(2).contains("~")) {
if (args.get(2).equals("~")) {
z = sender.getPos().getZ();
} else {
z = Float.parseFloat(args.get(2).replace("~", "")) + sender.getPos().getZ();
}
} else {
z = Float.parseFloat(args.get(2));
}
int sceneId = sender.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);
if (!result) {
CommandHandler.sendMessage(sender, "Invalid position.");
}
} catch (NumberFormatException ignored) {
CommandHandler.sendMessage(sender, "Invalid position.");
}
}
}
...@@ -31,6 +31,7 @@ public class GenshinData { ...@@ -31,6 +31,7 @@ public class GenshinData {
private static final Int2ObjectMap<AvatarSkillDepotData> avatarSkillDepotDataMap = new Int2ObjectOpenHashMap<>(); private static final Int2ObjectMap<AvatarSkillDepotData> avatarSkillDepotDataMap = new Int2ObjectOpenHashMap<>();
private static final Int2ObjectMap<AvatarSkillData> avatarSkillDataMap = new Int2ObjectOpenHashMap<>(); private static final Int2ObjectMap<AvatarSkillData> avatarSkillDataMap = new Int2ObjectOpenHashMap<>();
private static final Int2ObjectMap<AvatarCurveData> avatarCurveDataMap = new Int2ObjectLinkedOpenHashMap<>(); private static final Int2ObjectMap<AvatarCurveData> avatarCurveDataMap = new Int2ObjectLinkedOpenHashMap<>();
private static final Int2ObjectMap<AvatarFetterLevelData> avatarFetterLevelDataMap = new Int2ObjectOpenHashMap<>();
private static final Int2ObjectMap<AvatarPromoteData> avatarPromoteDataMap = new Int2ObjectOpenHashMap<>(); private static final Int2ObjectMap<AvatarPromoteData> avatarPromoteDataMap = new Int2ObjectOpenHashMap<>();
private static final Int2ObjectMap<AvatarTalentData> avatarTalentDataMap = new Int2ObjectOpenHashMap<>(); private static final Int2ObjectMap<AvatarTalentData> avatarTalentDataMap = new Int2ObjectOpenHashMap<>();
private static final Int2ObjectMap<ProudSkillData> proudSkillDataMap = new Int2ObjectOpenHashMap<>(); private static final Int2ObjectMap<ProudSkillData> proudSkillDataMap = new Int2ObjectOpenHashMap<>();
...@@ -57,6 +58,8 @@ public class GenshinData { ...@@ -57,6 +58,8 @@ public class GenshinData {
private static final Int2ObjectMap<SceneData> sceneDataMap = new Int2ObjectLinkedOpenHashMap<>(); private static final Int2ObjectMap<SceneData> sceneDataMap = new Int2ObjectLinkedOpenHashMap<>();
private static final Int2ObjectMap<FetterData> fetterDataMap = new Int2ObjectOpenHashMap<>(); private static final Int2ObjectMap<FetterData> fetterDataMap = new Int2ObjectOpenHashMap<>();
private static final Int2ObjectMap<FetterCharacterCardData> fetterCharacterCardDataMap = new Int2ObjectOpenHashMap<>();
private static final Int2ObjectMap<RewardData> rewardDataMap = new Int2ObjectOpenHashMap<>();
// Cache // Cache
private static Map<Integer, List<Integer>> fetters = new HashMap<>(); private static Map<Integer, List<Integer>> fetters = new HashMap<>();
...@@ -114,6 +117,14 @@ public class GenshinData { ...@@ -114,6 +117,14 @@ public class GenshinData {
return playerLevelDataMap; return playerLevelDataMap;
} }
public static Int2ObjectMap<AvatarFetterLevelData> getAvatarFetterLevelDataMap() {
return avatarFetterLevelDataMap;
}
public static Int2ObjectMap<FetterCharacterCardData> getFetterCharacterCardDataMap() {
return fetterCharacterCardDataMap;
}
public static Int2ObjectMap<AvatarLevelData> getAvatarLevelDataMap() { public static Int2ObjectMap<AvatarLevelData> getAvatarLevelDataMap() {
return avatarLevelDataMap; return avatarLevelDataMap;
} }
...@@ -176,6 +187,11 @@ public class GenshinData { ...@@ -176,6 +187,11 @@ public class GenshinData {
return levelData != null ? levelData.getExp() : 0; return levelData != null ? levelData.getExp() : 0;
} }
public static int getAvatarFetterLevelExpRequired(int level) {
AvatarFetterLevelData levelData = avatarFetterLevelDataMap.get(level);
return levelData != null ? levelData.getExp() : 0;
}
public static Int2ObjectMap<ProudSkillData> getProudSkillDataMap() { public static Int2ObjectMap<ProudSkillData> getProudSkillDataMap() {
return proudSkillDataMap; return proudSkillDataMap;
} }
...@@ -228,6 +244,10 @@ public class GenshinData { ...@@ -228,6 +244,10 @@ public class GenshinData {
return sceneDataMap; return sceneDataMap;
} }
public static Int2ObjectMap<RewardData> getRewardDataMap() {
return rewardDataMap;
}
public static Map<Integer, List<Integer>> getFetterDataEntries() { public static Map<Integer, List<Integer>> getFetterDataEntries() {
if (fetters.isEmpty()) { if (fetters.isEmpty()) {
fetterDataMap.forEach((k, v) -> { fetterDataMap.forEach((k, v) -> {
......
package emu.grasscutter.data.common;
import java.util.List;
public class OpenCondData {
private String CondType;
private List<Integer> ParamList;
public String getCondType() {
return CondType;
}
public void setCondType(String condType) {
CondType = condType;
}
public List<Integer> getParamList() {
return ParamList;
}
public void setParamList(List<Integer> paramList) {
ParamList = paramList;
}
}
package emu.grasscutter.data.common;
public class RewardItemData {
private int ItemId;
private int ItemCount;
public int getItemId() {
return ItemId;
}
public void setItemId(int itemId) {
ItemId = itemId;
}
public int getItemCount() {
return ItemCount;
}
public void setItemCount(int itemCount) {
ItemCount = itemCount;
}
}
...@@ -57,6 +57,8 @@ public class AvatarData extends GenshinResource { ...@@ -57,6 +57,8 @@ public class AvatarData extends GenshinResource {
private IntList abilities; private IntList abilities;
private List<Integer> fetters; private List<Integer> fetters;
private int nameCardRewardId;
private int nameCardId;
@Override @Override
public int getId(){ public int getId(){
...@@ -199,6 +201,14 @@ public class AvatarData extends GenshinResource { ...@@ -199,6 +201,14 @@ public class AvatarData extends GenshinResource {
return fetters; return fetters;
} }
public int getNameCardRewardId() {
return nameCardRewardId;
}
public int getNameCardId() {
return nameCardId;
}
@Override @Override
public void onLoad() { public void onLoad() {
this.skillDepot = GenshinData.getAvatarSkillDepotDataMap().get(this.SkillDepotId); this.skillDepot = GenshinData.getAvatarSkillDepotDataMap().get(this.SkillDepotId);
...@@ -206,6 +216,14 @@ public class AvatarData extends GenshinResource { ...@@ -206,6 +216,14 @@ public class AvatarData extends GenshinResource {
// Get fetters from GenshinData // Get fetters from GenshinData
this.fetters = GenshinData.getFetterDataEntries().get(this.Id); this.fetters = GenshinData.getFetterDataEntries().get(this.Id);
if (GenshinData.getFetterCharacterCardDataMap().get(this.Id) != null) {
this.nameCardRewardId = GenshinData.getFetterCharacterCardDataMap().get(this.Id).getRewardId();
}
if (GenshinData.getRewardDataMap().get(this.nameCardRewardId) != null) {
this.nameCardId = GenshinData.getRewardDataMap().get(this.nameCardRewardId).getRewardItemList().get(0).getItemId();
}
int size = GenshinData.getAvatarCurveDataMap().size(); int size = GenshinData.getAvatarCurveDataMap().size();
this.hpGrowthCurve = new float[size]; this.hpGrowthCurve = new float[size];
this.attackGrowthCurve = new float[size]; this.attackGrowthCurve = new float[size];
......
package emu.grasscutter.data.def;
import emu.grasscutter.data.GenshinResource;
import emu.grasscutter.data.ResourceType;
@ResourceType(name = "AvatarFettersLevelExcelConfigData.json")
public class AvatarFetterLevelData extends GenshinResource {
private int FetterLevel;
private int NeedExp;
@Override
public int getId() {
return this.FetterLevel;
}
public int getLevel() {
return FetterLevel;
}
public int getExp() {
return NeedExp;
}
}
package emu.grasscutter.data.def;
import emu.grasscutter.data.GenshinResource;
import emu.grasscutter.data.ResourceType;
import emu.grasscutter.data.ResourceType.LoadPriority;
@ResourceType(name = "FetterCharacterCardExcelConfigData.json", loadPriority = LoadPriority.HIGHEST)
public class FetterCharacterCardData extends GenshinResource {
private int AvatarId;
private int RewardId;
@Override
public int getId() {
return AvatarId;
}
public int getRewardId() {
return RewardId;
}
@Override
public void onLoad() {
}
}
package emu.grasscutter.data.def; package emu.grasscutter.data.def;
import java.util.List;
import emu.grasscutter.data.GenshinResource; import emu.grasscutter.data.GenshinResource;
import emu.grasscutter.data.ResourceType; import emu.grasscutter.data.ResourceType;
import emu.grasscutter.data.ResourceType.LoadPriority; import emu.grasscutter.data.ResourceType.LoadPriority;
import emu.grasscutter.data.common.OpenCondData;
@ResourceType(name = {"FetterInfoExcelConfigData.json", "FettersExcelConfigData.json", "FetterStoryExcelConfigData.json"}, loadPriority = LoadPriority.HIGHEST) @ResourceType(name = {"FetterInfoExcelConfigData.json", "FettersExcelConfigData.json", "FetterStoryExcelConfigData.json"}, loadPriority = LoadPriority.HIGHEST)
public class FetterData extends GenshinResource { public class FetterData extends GenshinResource {
private int AvatarId; private int AvatarId;
private int FetterId; private int FetterId;
private List<OpenCondData> OpenCond;
@Override @Override
public int getId() { public int getId() {
...@@ -18,6 +22,10 @@ public class FetterData extends GenshinResource { ...@@ -18,6 +22,10 @@ public class FetterData extends GenshinResource {
return AvatarId; return AvatarId;
} }
public List<OpenCondData> getOpenConds() {
return OpenCond;
}
@Override @Override
public void onLoad() { public void onLoad() {
} }
......
package emu.grasscutter.data.def;
import java.util.List;
import emu.grasscutter.data.GenshinResource;
import emu.grasscutter.data.ResourceType;
import emu.grasscutter.data.common.RewardItemData;
@ResourceType(name = "RewardExcelConfigData.json")
public class RewardData extends GenshinResource {
public int RewardId;
public List<RewardItemData> RewardItemList;
@Override
public int getId() {
return RewardId;
}
public List<RewardItemData> getRewardItemList() {
return RewardItemList;
}
@Override
public void onLoad() {
}
}
...@@ -101,7 +101,7 @@ public final class DatabaseManager { ...@@ -101,7 +101,7 @@ public final class DatabaseManager {
} }
public static synchronized int getNextId(Class<?> c) { public static synchronized int getNextId(Class<?> c) {
DatabaseCounter counter = getDatastore().find(DatabaseCounter.class).filter(Filters.eq("_id", c.getName())).first(); DatabaseCounter counter = getDatastore().find(DatabaseCounter.class).filter(Filters.eq("_id", c.getSimpleName())).first();
if (counter == null) { if (counter == null) {
counter = new DatabaseCounter(c.getSimpleName()); counter = new DatabaseCounter(c.getSimpleName());
} }
......
...@@ -35,7 +35,30 @@ import emu.grasscutter.net.proto.SocialDetailOuterClass.SocialDetail; ...@@ -35,7 +35,30 @@ import emu.grasscutter.net.proto.SocialDetailOuterClass.SocialDetail;
import emu.grasscutter.net.proto.WorldPlayerLocationInfoOuterClass.WorldPlayerLocationInfo; import emu.grasscutter.net.proto.WorldPlayerLocationInfoOuterClass.WorldPlayerLocationInfo;
import emu.grasscutter.server.game.GameServer; import emu.grasscutter.server.game.GameServer;
import emu.grasscutter.server.game.GameSession; import emu.grasscutter.server.game.GameSession;
import emu.grasscutter.server.packet.send.*; import emu.grasscutter.server.packet.send.PacketAbilityInvocationsNotify;
import emu.grasscutter.server.packet.send.PacketAvatarAddNotify;
import emu.grasscutter.server.packet.send.PacketAvatarDataNotify;
import emu.grasscutter.server.packet.send.PacketAvatarGainCostumeNotify;
import emu.grasscutter.server.packet.send.PacketAvatarGainFlycloakNotify;
import emu.grasscutter.server.packet.send.PacketClientAbilityInitFinishNotify;
import emu.grasscutter.server.packet.send.PacketCombatInvocationsNotify;
import emu.grasscutter.server.packet.send.PacketGadgetInteractRsp;
import emu.grasscutter.server.packet.send.PacketItemAddHintNotify;
import emu.grasscutter.server.packet.send.PacketOpenStateUpdateNotify;
import emu.grasscutter.server.packet.send.PacketPlayerApplyEnterMpResultNotify;
import emu.grasscutter.server.packet.send.PacketPlayerDataNotify;
import emu.grasscutter.server.packet.send.PacketPlayerEnterSceneNotify;
import emu.grasscutter.server.packet.send.PacketPlayerPropNotify;
import emu.grasscutter.server.packet.send.PacketPlayerStoreNotify;
import emu.grasscutter.server.packet.send.PacketPrivateChatNotify;
import emu.grasscutter.server.packet.send.PacketScenePlayerLocationNotify;
import emu.grasscutter.server.packet.send.PacketPlayerLevelRewardUpdateNotify;
import emu.grasscutter.server.packet.send.PacketSetNameCardRsp;
import emu.grasscutter.server.packet.send.PacketStoreWeightLimitNotify;
import emu.grasscutter.server.packet.send.PacketUnlockNameCardNotify;
import emu.grasscutter.server.packet.send.PacketWorldPlayerLocationNotify;
import emu.grasscutter.server.packet.send.PacketWorldPlayerRTTNotify;
import emu.grasscutter.server.packet.send.PacketMailChangeNotify;
import emu.grasscutter.utils.Position; import emu.grasscutter.utils.Position;
import it.unimi.dsi.fastutil.ints.Int2ObjectMap; import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
...@@ -75,6 +98,7 @@ public class GenshinPlayer { ...@@ -75,6 +98,7 @@ public class GenshinPlayer {
private MpSettingType mpSetting = MpSettingType.MpSettingEnterAfterApply; private MpSettingType mpSetting = MpSettingType.MpSettingEnterAfterApply;
private boolean showAvatar; private boolean showAvatar;
private ArrayList<AvatarProfileData> shownAvatars; private ArrayList<AvatarProfileData> shownAvatars;
private Set<Integer> rewardedLevels;
private ArrayList<Mail> mail; private ArrayList<Mail> mail;
private int sceneId; private int sceneId;
...@@ -125,6 +149,7 @@ public class GenshinPlayer { ...@@ -125,6 +149,7 @@ public class GenshinPlayer {
this.clientAbilityInitFinishHandler = new InvokeHandler(PacketClientAbilityInitFinishNotify.class); this.clientAbilityInitFinishHandler = new InvokeHandler(PacketClientAbilityInitFinishNotify.class);
this.birthday = new PlayerBirthday(); this.birthday = new PlayerBirthday();
this.rewardedLevels = new HashSet<>();
} }
// On player creation // On player creation
...@@ -648,6 +673,14 @@ public class GenshinPlayer { ...@@ -648,6 +673,14 @@ public class GenshinPlayer {
this.updateProfile(); this.updateProfile();
} }
public Set<Integer> getRewardedLevels() {
return rewardedLevels;
}
public void setRewardedLevels(Set<Integer> rewardedLevels) {
this.rewardedLevels = rewardedLevels;
}
public SocialDetail.Builder getSocialDetail() { public SocialDetail.Builder getSocialDetail() {
SocialDetail.Builder social = SocialDetail.newBuilder() SocialDetail.Builder social = SocialDetail.newBuilder()
.setUid(this.getUid()) .setUid(this.getUid())
...@@ -765,6 +798,7 @@ public class GenshinPlayer { ...@@ -765,6 +798,7 @@ public class GenshinPlayer {
session.send(new PacketAvatarDataNotify(this)); session.send(new PacketAvatarDataNotify(this));
session.send(new PacketPlayerEnterSceneNotify(this)); // Enter game world session.send(new PacketPlayerEnterSceneNotify(this)); // Enter game world
session.send(new PacketPlayerLevelRewardUpdateNotify(rewardedLevels));
session.send(new PacketOpenStateUpdateNotify()); session.send(new PacketOpenStateUpdateNotify());
// First notify packets sent // First notify packets sent
......
...@@ -90,6 +90,12 @@ public class GenshinAvatar { ...@@ -90,6 +90,12 @@ public class GenshinAvatar {
private int costume; private int costume;
private int bornTime; private int bornTime;
private int fetterLevel = 1;
private int fetterExp;
private int nameCardRewardId;
private int nameCardId;
public GenshinAvatar() { public GenshinAvatar() {
// Morhpia only! // Morhpia only!
this.equips = new Int2ObjectOpenHashMap<>(); this.equips = new Int2ObjectOpenHashMap<>();
...@@ -107,6 +113,8 @@ public class GenshinAvatar { ...@@ -107,6 +113,8 @@ public class GenshinAvatar {
public GenshinAvatar(AvatarData data) { public GenshinAvatar(AvatarData data) {
this(); this();
this.avatarId = data.getId(); this.avatarId = data.getId();
this.nameCardRewardId = data.getNameCardRewardId();
this.nameCardId = data.getNameCardId();
this.data = data; this.data = data;
this.bornTime = (int) (System.currentTimeMillis() / 1000); this.bornTime = (int) (System.currentTimeMillis() / 1000);
this.flyCloak = 140001; this.flyCloak = 140001;
...@@ -169,6 +177,14 @@ public class GenshinAvatar { ...@@ -169,6 +177,14 @@ public class GenshinAvatar {
this.satiation = satiation; this.satiation = satiation;
} }
public int getNameCardRewardId() {
return nameCardRewardId;
}
public void setNameCardRewardId(int nameCardRewardId) {
this.nameCardRewardId = nameCardRewardId;
}
public int getSatiationPenalty() { public int getSatiationPenalty() {
return satiationPenalty; return satiationPenalty;
} }
...@@ -281,6 +297,30 @@ public class GenshinAvatar { ...@@ -281,6 +297,30 @@ public class GenshinAvatar {
return fetters; return fetters;
} }
public int getFetterLevel() {
return fetterLevel;
}
public void setFetterLevel(int fetterLevel) {
this.fetterLevel = fetterLevel;
}
public int getFetterExp() {
return fetterExp;
}
public void setFetterExp(int fetterExp) {
this.fetterExp = fetterExp;
}
public int getNameCardId() {
return nameCardId;
}
public void setNameCardId(int nameCardId) {
this.nameCardId = nameCardId;
}
public float getCurrentHp() { public float getCurrentHp() {
return currentHp; return currentHp;
} }
...@@ -403,6 +443,8 @@ public class GenshinAvatar { ...@@ -403,6 +443,8 @@ public class GenshinAvatar {
// Fetters // Fetters
this.setFetterList(data.getFetters()); this.setFetterList(data.getFetters());
this.setNameCardRewardId(data.getNameCardRewardId());
this.setNameCardId(data.getNameCardId());
// Get hp percent, set to 100% if none // Get hp percent, set to 100% if none
float hpPercent = this.getFightProperty(FightProperty.FIGHT_PROP_MAX_HP) <= 0 ? 1f : this.getFightProperty(FightProperty.FIGHT_PROP_CUR_HP) / this.getFightProperty(FightProperty.FIGHT_PROP_MAX_HP); float hpPercent = this.getFightProperty(FightProperty.FIGHT_PROP_MAX_HP) <= 0 ? 1f : this.getFightProperty(FightProperty.FIGHT_PROP_CUR_HP) / this.getFightProperty(FightProperty.FIGHT_PROP_MAX_HP);
...@@ -702,8 +744,8 @@ public class GenshinAvatar { ...@@ -702,8 +744,8 @@ public class GenshinAvatar {
public AvatarInfo toProto() { public AvatarInfo toProto() {
AvatarFetterInfo.Builder avatarFetter = AvatarFetterInfo.newBuilder() AvatarFetterInfo.Builder avatarFetter = AvatarFetterInfo.newBuilder()
.setExpLevel(10) .setExpLevel(this.getFetterLevel())
.setExpNumber(6325); // Highest Level .setExpNumber(this.getFetterExp());
if (this.getFetterList() != null) { if (this.getFetterList() != null) {
for (int i = 0; i < this.getFetterList().size(); i++) { for (int i = 0; i < this.getFetterList().size(); i++) {
...@@ -715,6 +757,13 @@ public class GenshinAvatar { ...@@ -715,6 +757,13 @@ public class GenshinAvatar {
} }
} }
int rewardId = this.getNameCardRewardId();
int cardId = this.getNameCardId();
if (this.getPlayer().getNameCardList().contains(cardId)) {
avatarFetter.addRewardedFetterLevelList(rewardId);
}
AvatarInfo.Builder avatarInfo = AvatarInfo.newBuilder() AvatarInfo.Builder avatarInfo = AvatarInfo.newBuilder()
.setAvatarId(this.getAvatarId()) .setAvatarId(this.getAvatarId())
.setGuid(this.getGuid()) .setGuid(this.getGuid())
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment