Commit 2e69a4d8 authored by Akka's avatar Akka
Browse files

Merge remote-tracking branch 'origin/development' into tower

parents faa3cde5 c2a7d607
...@@ -10,7 +10,7 @@ import java.util.List; ...@@ -10,7 +10,7 @@ import java.util.List;
import static emu.grasscutter.utils.Language.translate; import static emu.grasscutter.utils.Language.translate;
@Command(label = "setworldlevel", usage = "setworldlevel <level>", @Command(label = "setworldlevel", usage = "setworldlevel <level>",
aliases = {"setworldlvl"}, permission = "player.setworldlevel", description = "commands.setWorldLevel.description") aliases = {"setworldlvl"}, permission = "player.setworldlevel", permissionTargeted = "player.setworldlevel.others", description = "commands.setWorldLevel.description")
public final class SetWorldLevelCommand implements CommandHandler { public final class SetWorldLevelCommand implements CommandHandler {
@Override @Override
......
...@@ -22,7 +22,7 @@ import java.util.Random; ...@@ -22,7 +22,7 @@ import java.util.Random;
import static emu.grasscutter.utils.Language.translate; import static emu.grasscutter.utils.Language.translate;
@Command(label = "spawn", usage = "spawn <entityId> [amount] [level(monster only)]", permission = "server.spawn", description = "commands.spawn.description") @Command(label = "spawn", usage = "spawn <entityId> [amount] [level(monster only)]", permission = "server.spawn", permissionTargeted = "server.spawn.others", description = "commands.spawn.description")
public final class SpawnCommand implements CommandHandler { public final class SpawnCommand implements CommandHandler {
@Override @Override
...@@ -46,13 +46,13 @@ public final class SpawnCommand implements CommandHandler { ...@@ -46,13 +46,13 @@ public final class SpawnCommand implements CommandHandler {
try { try {
amount = Integer.parseInt(args.get(1)); amount = Integer.parseInt(args.get(1));
} catch (NumberFormatException ignored) { } catch (NumberFormatException ignored) {
CommandHandler.sendMessage(sender, translate("commands.generic.error.amount")); CommandHandler.sendMessage(sender, translate("commands.generic.invalid.amount"));
} // Fallthrough } // Fallthrough
case 1: case 1:
try { try {
id = Integer.parseInt(args.get(0)); id = Integer.parseInt(args.get(0));
} catch (NumberFormatException ignored) { } catch (NumberFormatException ignored) {
CommandHandler.sendMessage(sender, translate("commands.generic.error.entityId")); CommandHandler.sendMessage(sender, translate("commands.generic.invalid.entityId"));
} }
break; break;
default: default:
...@@ -64,7 +64,7 @@ public final class SpawnCommand implements CommandHandler { ...@@ -64,7 +64,7 @@ public final class SpawnCommand implements CommandHandler {
GadgetData gadgetData = GameData.getGadgetDataMap().get(id); GadgetData gadgetData = GameData.getGadgetDataMap().get(id);
ItemData itemData = GameData.getItemDataMap().get(id); ItemData itemData = GameData.getItemDataMap().get(id);
if (monsterData == null && gadgetData == null && itemData == null) { if (monsterData == null && gadgetData == null && itemData == null) {
CommandHandler.sendMessage(sender, translate("commands.generic.error.entityId")); CommandHandler.sendMessage(sender, translate("commands.generic.invalid.entityId"));
return; return;
} }
Scene scene = targetPlayer.getScene(); Scene scene = targetPlayer.getScene();
......
...@@ -14,7 +14,7 @@ import java.util.List; ...@@ -14,7 +14,7 @@ import java.util.List;
import static emu.grasscutter.utils.Language.translate; import static emu.grasscutter.utils.Language.translate;
@Command(label = "talent", usage = "talent <talentID> <value>", permission = "player.settalent", description = "commands.talent.description") @Command(label = "talent", usage = "talent <talentID> <value>", permission = "player.settalent", permissionTargeted = "player.settalent.others", description = "commands.talent.description")
public final class TalentCommand implements CommandHandler { public final class TalentCommand implements CommandHandler {
private void setTalentLevel(Player sender, Player player, Avatar avatar, int talentId, int talentLevel) { private void setTalentLevel(Player sender, Player player, Avatar avatar, int talentId, int talentLevel) {
int oldLevel = avatar.getSkillLevelMap().get(talentId); int oldLevel = avatar.getSkillLevelMap().get(talentId);
...@@ -24,7 +24,7 @@ public final class TalentCommand implements CommandHandler { ...@@ -24,7 +24,7 @@ public final class TalentCommand implements CommandHandler {
} }
// Upgrade skill // Upgrade skill
avatar.getSkillLevelMap().put(talentLevel, talentLevel); avatar.getSkillLevelMap().put(talentId, talentLevel);
avatar.save(); avatar.save();
// Packet // Packet
......
...@@ -10,7 +10,7 @@ import java.util.List; ...@@ -10,7 +10,7 @@ import java.util.List;
import static emu.grasscutter.utils.Language.translate; import static emu.grasscutter.utils.Language.translate;
@Command(label = "tpall", usage = "tpall", permission = "player.tpall", description = "commands.teleportAll.description") @Command(label = "tpall", usage = "tpall", permission = "player.tpall", permissionTargeted = "player.tpall.others", description = "commands.teleportAll.description")
public final class TeleportAllCommand implements CommandHandler { public final class TeleportAllCommand implements CommandHandler {
@Override @Override
......
...@@ -10,7 +10,7 @@ import java.util.List; ...@@ -10,7 +10,7 @@ import java.util.List;
import static emu.grasscutter.utils.Language.translate; import static emu.grasscutter.utils.Language.translate;
@Command(label = "teleport", usage = "teleport <x> <y> <z> [scene id]", aliases = {"tp"}, permission = "player.teleport", description = "commands.teleport.description") @Command(label = "teleport", usage = "teleport <x> <y> <z> [scene id]", aliases = {"tp"}, permission = "player.teleport", permissionTargeted = "player.teleport.others", description = "commands.teleport.description")
public final class TeleportCommand implements CommandHandler { public final class TeleportCommand implements CommandHandler {
private float parseRelative(String input, Float current) { // TODO: Maybe this will be useful elsewhere later private float parseRelative(String input, Float current) { // TODO: Maybe this will be useful elsewhere later
......
...@@ -10,7 +10,7 @@ import java.util.List; ...@@ -10,7 +10,7 @@ import java.util.List;
import static emu.grasscutter.utils.Language.translate; import static emu.grasscutter.utils.Language.translate;
@Command(label = "unlocktower", usage = "unlocktower", aliases = {"ut"}, @Command(label = "unlocktower", usage = "unlocktower", aliases = {"ut"},
description = "Unlock all levels of tower", permission = "player.tower") description = "commands.unlocktower.description", permission = "player.tower")
public class UnlockTowerCommand implements CommandHandler { public class UnlockTowerCommand implements CommandHandler {
@Override @Override
...@@ -21,7 +21,7 @@ public class UnlockTowerCommand implements CommandHandler { ...@@ -21,7 +21,7 @@ public class UnlockTowerCommand implements CommandHandler {
unlockFloor(sender, sender.getServer().getTowerScheduleManager() unlockFloor(sender, sender.getServer().getTowerScheduleManager()
.getScheduleFloors()); .getScheduleFloors());
CommandHandler.sendMessage(sender, translate("commands.tower.unlock_done")); CommandHandler.sendMessage(sender, translate("commands.unlocktower.success"));
} }
public void unlockFloor(Player player, List<Integer> floors){ public void unlockFloor(Player player, List<Integer> floors){
......
...@@ -11,7 +11,7 @@ import java.util.List; ...@@ -11,7 +11,7 @@ import java.util.List;
import static emu.grasscutter.utils.Language.translate; import static emu.grasscutter.utils.Language.translate;
@Command(label = "weather", usage = "weather <weatherId> [climateId]", aliases = {"w"}, permission = "player.weather", description = "commands.weather.description") @Command(label = "weather", usage = "weather <weatherId> [climateId]", aliases = {"w"}, permission = "player.weather", permissionTargeted = "player.weather.others", description = "commands.weather.description")
public final class WeatherCommand implements CommandHandler { public final class WeatherCommand implements CommandHandler {
@Override @Override
......
package emu.grasscutter.game; package emu.grasscutter.game;
import dev.morphia.annotations.*; import dev.morphia.annotations.*;
import emu.grasscutter.Grasscutter;
import emu.grasscutter.database.DatabaseHelper; import emu.grasscutter.database.DatabaseHelper;
import emu.grasscutter.utils.Crypto; import emu.grasscutter.utils.Crypto;
import emu.grasscutter.utils.Utils; import emu.grasscutter.utils.Utils;
...@@ -107,11 +108,41 @@ public class Account { ...@@ -107,11 +108,41 @@ public class Account {
this.permissions.add(permission); return true; this.permissions.add(permission); return true;
} }
public static boolean permissionMatchesWildcard(String wildcard, String[] permissionParts) {
String[] wildcardParts = wildcard.split("\\.");
if (permissionParts.length < wildcardParts.length) { // A longer wildcard can never match a shorter permission
return false;
}
for (int i=0; i<wildcardParts.length; i++) {
switch (wildcardParts[i]) {
case "**": // Recursing match
return true;
case "*": // Match only one layer
if (i >= (permissionParts.length-1)) {
return true;
}
break;
default: // This layer isn't a wildcard, it needs to match exactly
if (!wildcardParts[i].equals(permissionParts[i])) {
return false;
}
}
}
// At this point the wildcard will have matched every layer, but if it is shorter then the permission then this is not a match at this point (no **).
return (wildcardParts.length == permissionParts.length);
}
public boolean hasPermission(String permission) { public boolean hasPermission(String permission) {
return this.permissions.contains(permission) || if (this.permissions.contains(permission) || this.permissions.contains("*")) {
this.permissions.contains("*") || return true;
(this.permissions.contains("player") || this.permissions.contains("player.*")) && permission.startsWith("player.") || }
(this.permissions.contains("server") || this.permissions.contains("server.*")) && permission.startsWith("server."); String[] permissionParts = permission.split("\\.");
for (String p : this.permissions) {
if (permissionMatchesWildcard(p, permissionParts)) {
return true;
}
}
return false;
} }
public boolean removePermission(String permission) { public boolean removePermission(String permission) {
......
...@@ -190,14 +190,17 @@ public class StaminaManager { ...@@ -190,14 +190,17 @@ public class StaminaManager {
// Returns new stamina and sends PlayerPropNotify // Returns new stamina and sends PlayerPropNotify
public int setStamina(GameSession session, String reason, int newStamina) { public int setStamina(GameSession session, String reason, int newStamina) {
// set stamina if (Grasscutter.getConfig().OpenStamina) {
player.setProperty(PlayerProperty.PROP_CUR_PERSIST_STAMINA, newStamina); // set stamina
session.send(new PacketPlayerPropNotify(player, PlayerProperty.PROP_CUR_PERSIST_STAMINA)); player.setProperty(PlayerProperty.PROP_CUR_PERSIST_STAMINA, newStamina);
// notify updated session.send(new PacketPlayerPropNotify(player, PlayerProperty.PROP_CUR_PERSIST_STAMINA));
for (Map.Entry<String, AfterUpdateStaminaListener> listener : afterUpdateStaminaListeners.entrySet()) { // notify updated
listener.getValue().onAfterUpdateStamina(reason, newStamina); for (Map.Entry<String, AfterUpdateStaminaListener> listener : afterUpdateStaminaListeners.entrySet()) {
listener.getValue().onAfterUpdateStamina(reason, newStamina);
}
return newStamina;
} }
return newStamina; return player.getProperty(PlayerProperty.PROP_CUR_PERSIST_STAMINA);
} }
// Kills avatar, removes entity and sends notification. // Kills avatar, removes entity and sends notification.
...@@ -243,15 +246,16 @@ public class StaminaManager { ...@@ -243,15 +246,16 @@ public class StaminaManager {
cachedEntity = entity; cachedEntity = entity;
MotionInfo motionInfo = moveInfo.getMotionInfo(); MotionInfo motionInfo = moveInfo.getMotionInfo();
MotionState motionState = motionInfo.getState(); MotionState motionState = motionInfo.getState();
boolean isReliable = moveInfo.getIsReliable(); int notifyEntityId = entity.getId();
Grasscutter.getLogger().trace("" + motionState + "\t" + (isReliable ? "reliable" : "")); int currentAvatarEntityId = session.getPlayer().getTeamManager().getCurrentAvatarEntity().getId();
if (isReliable) { if (notifyEntityId != currentAvatarEntityId) {
currentState = motionState; return;
Vector posVector = motionInfo.getPos(); }
Position newPos = new Position(posVector.getX(), posVector.getY(), posVector.getZ()); currentState = motionState;
if (newPos.getX() != 0 && newPos.getY() != 0 && newPos.getZ() != 0) { Vector posVector = motionInfo.getPos();
currentCoordinates = newPos; Position newPos = new Position(posVector.getX(), posVector.getY(), posVector.getZ());
} if (newPos.getX() != 0 && newPos.getY() != 0 && newPos.getZ() != 0) {
currentCoordinates = newPos;
} }
startSustainedStaminaHandler(); startSustainedStaminaHandler();
handleImmediateStamina(session, motionInfo, motionState, entity); handleImmediateStamina(session, motionInfo, motionState, entity);
...@@ -287,50 +291,48 @@ public class StaminaManager { ...@@ -287,50 +291,48 @@ public class StaminaManager {
private class SustainedStaminaHandler extends TimerTask { private class SustainedStaminaHandler extends TimerTask {
public void run() { public void run() {
if (Grasscutter.getConfig().OpenStamina) { boolean moving = isPlayerMoving();
boolean moving = isPlayerMoving(); int currentStamina = player.getProperty(PlayerProperty.PROP_CUR_PERSIST_STAMINA);
int currentStamina = player.getProperty(PlayerProperty.PROP_CUR_PERSIST_STAMINA); int maxStamina = player.getProperty(PlayerProperty.PROP_MAX_STAMINA);
int maxStamina = player.getProperty(PlayerProperty.PROP_MAX_STAMINA); if (moving || (currentStamina < maxStamina)) {
if (moving || (currentStamina < maxStamina)) { Grasscutter.getLogger().trace("Player moving: " + moving + ", stamina full: " +
Grasscutter.getLogger().trace("Player moving: " + moving + ", stamina full: " + (currentStamina >= maxStamina) + ", recalculate stamina");
(currentStamina >= maxStamina) + ", recalculate stamina");
Consumption consumption = new Consumption(ConsumptionType.None);
Consumption consumption = new Consumption(ConsumptionType.None); if (MotionStatesCategorized.get("CLIMB").contains(currentState)) {
if (MotionStatesCategorized.get("CLIMB").contains(currentState)) { consumption = getClimbSustainedConsumption();
consumption = getClimbSustainedConsumption(); } else if (MotionStatesCategorized.get("SWIM").contains((currentState))) {
} else if (MotionStatesCategorized.get("SWIM").contains((currentState))) { consumption = getSwimSustainedConsumptions();
consumption = getSwimSustainedConsumptions(); } else if (MotionStatesCategorized.get("RUN").contains(currentState)) {
} else if (MotionStatesCategorized.get("RUN").contains(currentState)) { consumption = getRunWalkDashSustainedConsumption();
consumption = getRunWalkDashSustainedConsumption(); } else if (MotionStatesCategorized.get("FLY").contains(currentState)) {
} else if (MotionStatesCategorized.get("FLY").contains(currentState)) { consumption = getFlySustainedConsumption();
consumption = getFlySustainedConsumption(); } else if (MotionStatesCategorized.get("STANDBY").contains(currentState)) {
} else if (MotionStatesCategorized.get("STANDBY").contains(currentState)) { consumption = getStandSustainedConsumption();
consumption = getStandSustainedConsumption(); }
}
/* /*
TODO: Reductions that apply to all motion types: TODO: Reductions that apply to all motion types:
Elemental Resonance Elemental Resonance
Wind: -15% Wind: -15%
Skills Skills
Diona E: -10% while shield lasts Diona E: -10% while shield lasts
Barbara E: -12% while lasts Barbara E: -12% while lasts
*/ */
if (cachedSession != null) { if (cachedSession != null) {
if (consumption.amount < 0) { if (consumption.amount < 0) {
staminaRecoverDelay = 0; staminaRecoverDelay = 0;
} }
if (consumption.amount > 0 && consumption.consumptionType != ConsumptionType.POWERED_FLY) { if (consumption.amount > 0 && consumption.consumptionType != ConsumptionType.POWERED_FLY) {
// For POWERED_FLY recover immediately - things like Amber's gliding exam may require this. // For POWERED_FLY recover immediately - things like Amber's gliding exam may require this.
if (staminaRecoverDelay < 10) { if (staminaRecoverDelay < 10) {
// For others recover after 2 seconds (10 ticks) - as official server does. // For others recover after 2 seconds (10 ticks) - as official server does.
staminaRecoverDelay++; staminaRecoverDelay++;
consumption.amount = 0; consumption.amount = 0;
Grasscutter.getLogger().trace("[StaminaManager] Delaying recovery: " + staminaRecoverDelay); Grasscutter.getLogger().trace("[StaminaManager] Delaying recovery: " + staminaRecoverDelay);
}
} }
updateStaminaRelative(cachedSession, consumption);
} }
updateStaminaRelative(cachedSession, consumption);
} }
} }
previousState = currentState; previousState = currentState;
......
...@@ -79,6 +79,9 @@ public class ScriptMonsterTideService { ...@@ -79,6 +79,9 @@ public class ScriptMonsterTideService {
// fix the 5-2 // fix the 5-2
sceneScriptManager.callEvent(EventType.EVENT_MONSTER_TIDE_DIE, new ScriptArgs(monsterKillCount.get())); sceneScriptManager.callEvent(EventType.EVENT_MONSTER_TIDE_DIE, new ScriptArgs(monsterKillCount.get()));
} }
// spawn the last turn of monsters
// fix the 5-2
this.sceneScriptManager.callEvent(EventType.EVENT_MONSTER_TIDE_DIE, new ScriptArgs(this.monsterKillCount.get()));
} }
public void unload(){ public void unload(){
......
...@@ -334,6 +334,13 @@ ...@@ -334,6 +334,13 @@
}, },
"restart": { "restart": {
"description": "Restarts the current session" "description": "Restarts the current session"
},
"unlocktower": {
"success": "unlock done",
"description": "Unlock all levels of tower"
},
"resetshop": {
"description": "reset shop"
} }
} }
} }
...@@ -184,7 +184,7 @@ ...@@ -184,7 +184,7 @@
"account_error": "Konto nie może zostać znalezione." "account_error": "Konto nie może zostać znalezione."
}, },
"position": { "position": {
"success": "Koordynaty: %.3f, %.3f, %.3f\nID sceny: %d" "success": "Koordynaty: %s, %s, %s\nID sceny: %s"
}, },
"reload": { "reload": {
"reload_start": "Ponowne ładowanie konfiguracji.", "reload_start": "Ponowne ładowanie konfiguracji.",
...@@ -293,6 +293,13 @@ ...@@ -293,6 +293,13 @@
"usage": "Użycie: ", "usage": "Użycie: ",
"aliases": "Aliasy: ", "aliases": "Aliasy: ",
"available_commands": "Dostępne komendy: " "available_commands": "Dostępne komendy: "
},
"unlocktower": {
"success": "odblokować gotowe",
"description": "Odblokuj głęboką spiralę"
},
"resetshop": {
"description": "zresetuj sklep"
} }
} }
} }
\ No newline at end of file
...@@ -201,7 +201,7 @@ ...@@ -201,7 +201,7 @@
"description": "给予或移除指定玩家的权限。" "description": "给予或移除指定玩家的权限。"
}, },
"position": { "position": {
"success": "坐标:%.3f, %.3f, %.3f\n场景ID:%d", "success": "坐标:%s, %s, %s\n场景ID:%s",
"description": "获取所在位置。" "description": "获取所在位置。"
}, },
"reload": { "reload": {
...@@ -249,7 +249,7 @@ ...@@ -249,7 +249,7 @@
"setFetterLevel": { "setFetterLevel": {
"usage": "用法:setfetterlevel <level>", "usage": "用法:setfetterlevel <level>",
"range_error": "好感度等级必须在 0 到 10 之间。", "range_error": "好感度等级必须在 0 到 10 之间。",
"fetter_set_level": "好感度已设置为 %s 级", "success": "好感度已设置为 %s 级",
"level_error": "无效的好感度等级。", "level_error": "无效的好感度等级。",
"description": "设置当前角色的好感度等级。" "description": "设置当前角色的好感度等级。"
}, },
...@@ -330,6 +330,13 @@ ...@@ -330,6 +330,13 @@
}, },
"restart": { "restart": {
"description": "重新启动服务器。" "description": "重新启动服务器。"
},
"unlocktower": {
"success": "解锁完成。",
"description": "解锁深境螺旋的所有层"
},
"resetshop": {
"description": "重置商店时间"
} }
} }
} }
...@@ -184,7 +184,7 @@ ...@@ -184,7 +184,7 @@
"account_error": "The account cannot be found." "account_error": "The account cannot be found."
}, },
"position": { "position": {
"success": "坐標:%.3f, %.3f, %.3f\n場景ID:%d" "success": "坐標:%s, %s, %s\n場景ID:%s"
}, },
"reload": { "reload": {
"reload_start": "正在重新加載設定檔。", "reload_start": "正在重新加載設定檔。",
...@@ -226,7 +226,7 @@ ...@@ -226,7 +226,7 @@
"setFetterLevel": { "setFetterLevel": {
"usage": "用法:setfetterlevel <level>", "usage": "用法:setfetterlevel <level>",
"range_error": "好感度必須在 0 到 10 之間。", "range_error": "好感度必須在 0 到 10 之間。",
"fetter_set_level": "好感等級已設定為 %s", "success": "好感等級已設定為 %s",
"level_error": "無效的好感度。" "level_error": "無效的好感度。"
}, },
"setStats": { "setStats": {
...@@ -293,6 +293,13 @@ ...@@ -293,6 +293,13 @@
"usage": "用法:", "usage": "用法:",
"aliases": "別名:", "aliases": "別名:",
"available_commands": "可用指令:" "available_commands": "可用指令:"
},
"unlocktower": {
"success": "解鎖完成。",
"description": "解鎖所有級別的深境螺旋"
},
"resetshop": {
"description": "重置商店時間"
} }
} }
} }
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