mirror of
https://github.com/Grasscutters/Grasscutter.git
synced 2025-12-17 09:25:06 +01:00
Merge branch 'development' into tp
This commit is contained in:
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -83,6 +83,9 @@ public class GiveAllCommand implements CommandHandler {
|
||||
Avatar avatar = new Avatar(avatarData);
|
||||
avatar.setLevel(90);
|
||||
avatar.setPromoteLevel(6);
|
||||
for(int i = 1;i <= 6;++i){
|
||||
avatar.getTalentIdList().add((avatar.getAvatarId()-10000000)*10+i);
|
||||
}
|
||||
// This will handle stats and talents
|
||||
avatar.recalcStats();
|
||||
player.addAvatar(avatar);
|
||||
@@ -95,14 +98,14 @@ public class GiveAllCommand implements CommandHandler {
|
||||
if (isTestItem(itemdata.getId())) continue;
|
||||
|
||||
if (itemdata.isEquip()) {
|
||||
for (int i = 0; i < 5; ++i) {
|
||||
GameItem item = new GameItem(itemdata);
|
||||
if (itemdata.getItemType() == ItemType.ITEM_WEAPON) {
|
||||
if (itemdata.getItemType() == ItemType.ITEM_WEAPON) {
|
||||
for (int i = 0; i < 5; ++i) {
|
||||
GameItem item = new GameItem(itemdata);
|
||||
item.setLevel(90);
|
||||
item.setPromoteLevel(6);
|
||||
item.setRefinement(4);
|
||||
itemList.add(item);
|
||||
}
|
||||
itemList.add(item);
|
||||
}
|
||||
}
|
||||
else {
|
||||
|
||||
@@ -0,0 +1,89 @@
|
||||
package emu.grasscutter.command.commands;
|
||||
|
||||
import emu.grasscutter.Grasscutter;
|
||||
import emu.grasscutter.command.Command;
|
||||
import emu.grasscutter.command.CommandHandler;
|
||||
import emu.grasscutter.data.GameData;
|
||||
import emu.grasscutter.data.def.ItemData;
|
||||
import emu.grasscutter.game.inventory.GameItem;
|
||||
import emu.grasscutter.game.inventory.ItemType;
|
||||
import emu.grasscutter.game.player.Player;
|
||||
import emu.grasscutter.game.props.ActionReason;
|
||||
|
||||
import 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")
|
||||
public final class GiveArtifactCommand implements CommandHandler {
|
||||
@Override
|
||||
public void execute(Player sender, List<String> args) {
|
||||
int size = args.size(), target, itemId, mainPropId, level;
|
||||
ArrayList<Integer> appendPropIdList = new ArrayList<>();
|
||||
String msg = "Usage: giveart|givea [player] <artifactId> <mainPropId> [<appendPropId>[,<times>]]... [level]";
|
||||
|
||||
if (sender == null && size < 2) {
|
||||
CommandHandler.sendMessage(null, msg);
|
||||
return;
|
||||
}
|
||||
|
||||
if (size >= 2) {
|
||||
try {
|
||||
level = Integer.parseInt(args.get(size - 1));
|
||||
if (level <= 21) size--;
|
||||
else level = 1;
|
||||
target = Integer.parseInt(args.get(0));
|
||||
int fromIdx;
|
||||
if (Grasscutter.getGameServer().getPlayerByUid(target) == null && sender != null) {
|
||||
target = sender.getUid();
|
||||
itemId = Integer.parseInt(args.get(0));
|
||||
mainPropId = Integer.parseInt(args.get(1));
|
||||
fromIdx = 2;
|
||||
} else {
|
||||
target = Integer.parseInt(args.get(0));
|
||||
itemId = Integer.parseInt(args.get(1));
|
||||
mainPropId = Integer.parseInt(args.get(2));
|
||||
fromIdx = 3;
|
||||
}
|
||||
args.subList(fromIdx, size).forEach(it -> {
|
||||
String[] arr;
|
||||
int n = 1;
|
||||
if ((arr = it.split(",")).length == 2) {
|
||||
it = arr[0];
|
||||
n = Integer.parseInt(arr[1]);
|
||||
}
|
||||
appendPropIdList.addAll(Collections.nCopies(n, Integer.parseInt(it)));
|
||||
});
|
||||
} catch (Exception ignored) {
|
||||
CommandHandler.sendMessage(sender, msg);
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
CommandHandler.sendMessage(sender, msg);
|
||||
return;
|
||||
}
|
||||
|
||||
Player targetPlayer = Grasscutter.getGameServer().getPlayerByUid(target);
|
||||
if (targetPlayer == null) {
|
||||
CommandHandler.sendMessage(sender, "Player not found.");
|
||||
return;
|
||||
}
|
||||
|
||||
ItemData itemData = GameData.getItemDataMap().get(itemId);
|
||||
|
||||
if (itemData.getItemType() != ItemType.ITEM_RELIQUARY) {
|
||||
CommandHandler.sendMessage(sender, "Invalid artifact ID.");
|
||||
return;
|
||||
}
|
||||
|
||||
GameItem item = new GameItem(itemData);
|
||||
item.setLevel(level);
|
||||
item.setMainPropId(mainPropId);
|
||||
item.getAppendPropIdList().clear();//Clear default random props first
|
||||
item.getAppendPropIdList().addAll(appendPropIdList);
|
||||
targetPlayer.getInventory().addItem(item, ActionReason.SubfieldDrop);
|
||||
|
||||
CommandHandler.sendMessage(sender, String.format("Given %s to %s.", itemId, target));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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("*") ? true : false;
|
||||
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) {
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,24 +18,30 @@ import emu.grasscutter.net.proto.SceneEntityInfoOuterClass.SceneEntityInfo;
|
||||
import emu.grasscutter.net.proto.SceneGadgetInfoOuterClass.SceneGadgetInfo;
|
||||
import emu.grasscutter.net.proto.VectorOuterClass.Vector;
|
||||
import emu.grasscutter.net.proto.VehicleInfoOuterClass.*;
|
||||
|
||||
import emu.grasscutter.net.proto.VehicleMemberOuterClass.*;
|
||||
import emu.grasscutter.utils.Position;
|
||||
import emu.grasscutter.utils.ProtoHelper;
|
||||
|
||||
import it.unimi.dsi.fastutil.ints.Int2FloatMap;
|
||||
import it.unimi.dsi.fastutil.ints.Int2FloatOpenHashMap;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.ArrayList;
|
||||
|
||||
public class EntityVehicle extends EntityBaseGadget {
|
||||
|
||||
private final Player owner;
|
||||
private final Int2FloatOpenHashMap fightProp;
|
||||
|
||||
private final Position pos;
|
||||
private final Position rot;
|
||||
|
||||
private float curStamina;
|
||||
private final int pointId;
|
||||
private final int gadgetId;
|
||||
|
||||
private float curStamina;
|
||||
private List<VehicleMember> vehicleMembers;
|
||||
|
||||
public EntityVehicle(Scene scene, Player player, int gadgetId, int pointId, Position pos, Position rot) {
|
||||
super(scene);
|
||||
this.owner = player;
|
||||
@@ -46,6 +52,7 @@ public class EntityVehicle extends EntityBaseGadget {
|
||||
this.gadgetId = gadgetId;
|
||||
this.pointId = pointId;
|
||||
this.curStamina = 240;
|
||||
this.vehicleMembers = new ArrayList<VehicleMember>();
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -61,6 +68,8 @@ public class EntityVehicle extends EntityBaseGadget {
|
||||
|
||||
public int getPointId() { return pointId; }
|
||||
|
||||
public List<VehicleMember> getVehicleMembers() { return vehicleMembers; }
|
||||
|
||||
@Override
|
||||
public Int2FloatOpenHashMap getFightProperties() {
|
||||
return fightProp;
|
||||
|
||||
@@ -34,6 +34,10 @@ public abstract class GameEntity {
|
||||
return this.id;
|
||||
}
|
||||
|
||||
public int getEntityType() {
|
||||
return getId() >> 24;
|
||||
}
|
||||
|
||||
public World getWorld() {
|
||||
return this.getScene().getWorld();
|
||||
}
|
||||
|
||||
@@ -244,6 +244,10 @@ public class GameItem {
|
||||
return mainPropId;
|
||||
}
|
||||
|
||||
public void setMainPropId(int mainPropId) {
|
||||
this.mainPropId = mainPropId;
|
||||
}
|
||||
|
||||
public List<Integer> getAppendPropIdList() {
|
||||
return appendPropIdList;
|
||||
}
|
||||
|
||||
@@ -822,7 +822,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);
|
||||
}
|
||||
|
||||
@@ -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_WORLD) {
|
||||
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,11 +152,8 @@ 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
|
||||
try {
|
||||
cs.eval(getBindings());
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,15 @@
|
||||
package emu.grasscutter.server.packet.recv;
|
||||
|
||||
import emu.grasscutter.net.packet.Opcodes;
|
||||
import emu.grasscutter.net.packet.PacketHandler;
|
||||
import emu.grasscutter.net.packet.PacketOpcodes;
|
||||
import emu.grasscutter.server.game.GameSession;
|
||||
import emu.grasscutter.server.packet.send.PacketGetOnlinePlayerListRsp;
|
||||
|
||||
@Opcodes(PacketOpcodes.GetOnlinePlayerListReq)
|
||||
public class HandlerGetOnlinePlayerListReq extends PacketHandler {
|
||||
@Override
|
||||
public void handle(GameSession session, byte[] header, byte[] payload) throws Exception {
|
||||
session.send(new PacketGetOnlinePlayerListRsp(session.getPlayer()));
|
||||
}
|
||||
}
|
||||
@@ -17,11 +17,13 @@ public class PacketDungeonEntryInfoRsp extends BasePacket {
|
||||
DungeonEntryInfoRsp.Builder proto = DungeonEntryInfoRsp.newBuilder()
|
||||
.setPointId(pointData.getId());
|
||||
|
||||
for (int dungeonId : pointData.getDungeonIds()) {
|
||||
DungeonEntryInfo info = DungeonEntryInfo.newBuilder().setDungeonId(dungeonId).build();
|
||||
proto.addDungeonEntryList(info);
|
||||
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,36 @@
|
||||
package emu.grasscutter.server.packet.send;
|
||||
|
||||
import emu.grasscutter.Grasscutter;
|
||||
import emu.grasscutter.game.player.Player;
|
||||
import emu.grasscutter.net.packet.BasePacket;
|
||||
import emu.grasscutter.net.packet.PacketOpcodes;
|
||||
import emu.grasscutter.net.proto.GetOnlinePlayerListReqOuterClass;
|
||||
import emu.grasscutter.net.proto.GetOnlinePlayerListRspOuterClass.*;
|
||||
import emu.grasscutter.net.proto.MpSettingTypeOuterClass;
|
||||
import emu.grasscutter.net.proto.OnlinePlayerInfoOuterClass.OnlinePlayerInfo;
|
||||
import emu.grasscutter.net.proto.ProfilePictureOuterClass.ProfilePicture;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
|
||||
public class PacketGetOnlinePlayerListRsp extends BasePacket {
|
||||
public PacketGetOnlinePlayerListRsp(Player session){
|
||||
super(PacketOpcodes.GetOnlinePlayerListRsp);
|
||||
|
||||
List<Player> players = Grasscutter.getGameServer().getPlayers().values().stream().limit(50).toList();
|
||||
|
||||
GetOnlinePlayerListRsp.Builder proto = GetOnlinePlayerListRsp.newBuilder();
|
||||
|
||||
if (players.size() != 0) {
|
||||
for(Player player : players) {
|
||||
if (player.getUid() == session.getUid()) continue;
|
||||
|
||||
proto.addPlayerInfoList(player.getOnlinePlayerInfo());
|
||||
}
|
||||
}
|
||||
|
||||
this.setData(proto);
|
||||
}
|
||||
}
|
||||
@@ -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,8 +13,12 @@ public class PacketGetScenePointRsp extends BasePacket {
|
||||
GetScenePointRsp.Builder p = GetScenePointRsp.newBuilder()
|
||||
.setSceneId(sceneId);
|
||||
|
||||
for (int i = 1; i < 1000; i++) {
|
||||
p.addUnlockedPointList(i);
|
||||
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++) {
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package emu.grasscutter.server.packet.send;
|
||||
|
||||
import emu.grasscutter.Grasscutter;
|
||||
import emu.grasscutter.game.entity.EntityVehicle;
|
||||
import emu.grasscutter.game.player.Player;
|
||||
import emu.grasscutter.game.entity.GameEntity;
|
||||
|
||||
@@ -17,16 +18,49 @@ public class PacketVehicleInteractRsp extends BasePacket {
|
||||
VehicleInteractRsp.Builder proto = VehicleInteractRsp.newBuilder();
|
||||
|
||||
GameEntity vehicle = player.getScene().getEntityById(entityId);
|
||||
if(vehicle != null) {
|
||||
|
||||
if(vehicle instanceof EntityVehicle) {
|
||||
proto.setEntityId(vehicle.getId());
|
||||
proto.setInteractType(interactType);
|
||||
|
||||
VehicleMember vehicleMember = VehicleMember.newBuilder()
|
||||
.setUid(player.getUid())
|
||||
.setAvatarGuid(player.getTeamManager().getCurrentCharacterGuid())
|
||||
.build();
|
||||
|
||||
proto.setInteractType(interactType);
|
||||
proto.setMember(vehicleMember);
|
||||
|
||||
switch(interactType){
|
||||
case VEHICLE_INTERACT_IN -> {
|
||||
((EntityVehicle) vehicle).getVehicleMembers().add(vehicleMember);
|
||||
}
|
||||
case VEHICLE_INTERACT_OUT -> {
|
||||
((EntityVehicle) vehicle).getVehicleMembers().remove(vehicleMember);
|
||||
}
|
||||
default -> {}
|
||||
}
|
||||
}
|
||||
this.setData(proto.build());
|
||||
}
|
||||
|
||||
public PacketVehicleInteractRsp(EntityVehicle vehicle, VehicleMember vehicleMember, VehicleInteractType interactType) {
|
||||
super(PacketOpcodes.VehicleInteractRsp);
|
||||
VehicleInteractRsp.Builder proto = VehicleInteractRsp.newBuilder();
|
||||
|
||||
if(vehicle != null) {
|
||||
proto.setEntityId(vehicle.getId());
|
||||
proto.setInteractType(interactType);
|
||||
proto.setMember(vehicleMember);
|
||||
|
||||
switch(interactType){
|
||||
case VEHICLE_INTERACT_IN -> {
|
||||
vehicle.getVehicleMembers().add(vehicleMember);
|
||||
}
|
||||
case VEHICLE_INTERACT_OUT -> {
|
||||
vehicle.getVehicleMembers().remove(vehicleMember);
|
||||
}
|
||||
default -> {}
|
||||
}
|
||||
}
|
||||
this.setData(proto.build());
|
||||
}
|
||||
|
||||
@@ -8,10 +8,16 @@ import emu.grasscutter.game.entity.GameEntity;
|
||||
|
||||
import emu.grasscutter.net.packet.BasePacket;
|
||||
import emu.grasscutter.net.packet.PacketOpcodes;
|
||||
|
||||
import emu.grasscutter.net.proto.VehicleMemberOuterClass.VehicleMember;
|
||||
import emu.grasscutter.net.proto.VehicleSpawnRspOuterClass.VehicleSpawnRsp;
|
||||
|
||||
import emu.grasscutter.utils.Position;
|
||||
import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
|
||||
import static emu.grasscutter.net.proto.VehicleInteractTypeOuterClass.VehicleInteractType.VEHICLE_INTERACT_OUT;
|
||||
|
||||
public class PacketVehicleSpawnRsp extends BasePacket {
|
||||
|
||||
@@ -19,6 +25,23 @@ public class PacketVehicleSpawnRsp extends BasePacket {
|
||||
super(PacketOpcodes.VehicleSpawnRsp);
|
||||
VehicleSpawnRsp.Builder proto = VehicleSpawnRsp.newBuilder();
|
||||
|
||||
// Eject vehicle members and Kill previous vehicles if there are any
|
||||
List<GameEntity> previousVehicles = player.getScene().getEntities().values().stream()
|
||||
.filter(entity -> entity instanceof EntityVehicle
|
||||
&& ((EntityVehicle) entity).getGadgetId() == vehicleId
|
||||
&& ((EntityVehicle) entity).getOwner().equals(player))
|
||||
.toList();
|
||||
|
||||
previousVehicles.stream().forEach(entity -> {
|
||||
List<VehicleMember> vehicleMembers = ((EntityVehicle) entity).getVehicleMembers().stream().toList();
|
||||
|
||||
vehicleMembers.stream().forEach(vehicleMember -> {
|
||||
player.getScene().broadcastPacket(new PacketVehicleInteractRsp(((EntityVehicle) entity), vehicleMember, VEHICLE_INTERACT_OUT));
|
||||
});
|
||||
|
||||
player.getScene().killEntity(entity, 0);
|
||||
});
|
||||
|
||||
EntityVehicle vehicle = new EntityVehicle(player.getScene(), player, vehicleId, pointId, pos, rot);
|
||||
|
||||
switch (vehicleId) {
|
||||
|
||||
Reference in New Issue
Block a user