From 15dca5a04ddbc3720da465ecb96159af61421c3b Mon Sep 17 00:00:00 2001 From: Luke H-W Date: Thu, 5 May 2022 22:53:48 +0930 Subject: [PATCH 01/11] GiveCommand: fix edge case with unspaced multiple args (#539) Co-authored-by: AnimeGitB --- src/main/java/emu/grasscutter/command/commands/GiveCommand.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/emu/grasscutter/command/commands/GiveCommand.java b/src/main/java/emu/grasscutter/command/commands/GiveCommand.java index c2039dece..f3f2adc17 100644 --- a/src/main/java/emu/grasscutter/command/commands/GiveCommand.java +++ b/src/main/java/emu/grasscutter/command/commands/GiveCommand.java @@ -20,7 +20,7 @@ import java.util.regex.Matcher; public final class GiveCommand implements CommandHandler { Pattern lvlRegex = Pattern.compile("l(?:vl?)?(\\d+)"); // Java is a joke of a proglang that doesn't have raw string literals Pattern refineRegex = Pattern.compile("r(\\d+)"); - Pattern amountRegex = Pattern.compile("((?<=x)\\d+|\\d+(?=x))"); + Pattern amountRegex = Pattern.compile("((?<=x)\\d+|\\d+(?=x)(?!x\\d))"); private int matchIntOrNeg(Pattern pattern, String arg) { Matcher match = pattern.matcher(arg); From 3395c76dbc190c7926bee7195f579a1d13338604 Mon Sep 17 00:00:00 2001 From: Benjamin Elsdon Date: Thu, 5 May 2022 15:59:48 +0800 Subject: [PATCH 02/11] Removed GCStatic. Cleaned up GachaRecordHandler. --- .gitignore | 1 + data/gacha_records.html | 2 +- .../java/emu/grasscutter/Grasscutter.java | 2 +- src/main/java/emu/grasscutter/Language.java | 285 ++++++++++++++++++ .../server/dispatch/DispatchServer.java | 19 +- .../http}/GachaRecordHandler.java | 5 +- .../http/gcstatic/StaticFileHandler.java | 31 -- .../java/emu/grasscutter/tools/Tools.java | 8 +- 8 files changed, 307 insertions(+), 46 deletions(-) create mode 100644 src/main/java/emu/grasscutter/Language.java rename src/main/java/emu/grasscutter/server/{http/gacha => dispatch/http}/GachaRecordHandler.java (88%) delete mode 100644 src/main/java/emu/grasscutter/server/http/gcstatic/StaticFileHandler.java diff --git a/.gitignore b/.gitignore index 239309c12..9c374fa70 100644 --- a/.gitignore +++ b/.gitignore @@ -67,3 +67,4 @@ mongod.exe /*.sh language/ languages/ +gacha_mappings.js diff --git a/data/gacha_records.html b/data/gacha_records.html index ef81edc4d..5ce8e660f 100644 --- a/data/gacha_records.html +++ b/data/gacha_records.html @@ -92,7 +92,7 @@ - + diff --git a/src/main/java/emu/grasscutter/Grasscutter.java b/src/main/java/emu/grasscutter/Grasscutter.java index f322e5fdf..a1c8a5c7c 100644 --- a/src/main/java/emu/grasscutter/Grasscutter.java +++ b/src/main/java/emu/grasscutter/Grasscutter.java @@ -76,7 +76,7 @@ public final class Grasscutter { Tools.createGmHandbook(); return; } case "-gachamap" -> { - Tools.createGachaMapping(); return; + Tools.createGachaMapping("./gacha_mappings.js"); return; } } } diff --git a/src/main/java/emu/grasscutter/Language.java b/src/main/java/emu/grasscutter/Language.java new file mode 100644 index 000000000..e5150a6fe --- /dev/null +++ b/src/main/java/emu/grasscutter/Language.java @@ -0,0 +1,285 @@ +package emu.grasscutter; + +public final class Language { + public String An_error_occurred_during_game_update = "An error occurred during game update."; + public String Starting_Grasscutter = "Starting Grasscutter..."; + public String Invalid_server_run_mode = "Invalid server run mode."; + public String Server_run_mode = "Server run mode must be 'HYBRID', 'DISPATCH_ONLY', or 'GAME_ONLY'. Unable to start Grasscutter..."; + public String Shutting_down = "Shutting down..."; + public String Start_done = "Done! For help, type \"help\""; + public String Dispatch_mode_not_support_command = "Commands are not supported in dispatch only mode."; + public String Command_error = "Command error:"; + public String error = "An error occurred."; + public String grasscutter_is_free = "Grasscutter is FREE software. If you have paid for this, you may have been scammed. Homepage: https://github.com/Grasscutters/Grasscutter"; + public String Game_start_port = "Game Server started on port %s"; + public String Client_connect = "Client connected from %s"; + public String Client_disconnect = "Client disconnected from %s"; + public String Client_request = "[Dispatch] Client %s %s request: %s"; + public String Not_load_keystore = "[Dispatch] Unable to load keystore. Trying default keystore password..."; + public String Use_default_keystore = "[Dispatch] The default keystore password was loaded successfully. Please consider setting the password to 123456 in config.json."; + public String Load_keystore_error = "[Dispatch] Error while loading keystore!"; + public String Not_find_ssl_cert = "[Dispatch] No SSL cert found! Falling back to HTTP server."; + public String Welcome = "Welcome to Grasscutter"; + public String Potential_unhandled_request = "[Dispatch] Potential unhandled %s request: %s"; + public String Client_login_token = "[Dispatch] Client %s is trying to log in via token"; + public String Client_token_login_failed = "[Dispatch] Client %s failed to log in via token"; + public String Client_login_in_token = "[Dispatch] Client %s logged in via token as %s"; + public String Game_account_cache_error = "Game account cache information error"; + public String Wrong_session_key = "Wrong session key."; + public String Client_exchange_combo_token = "[Dispatch] Client %s succeed to exchange combo token"; + public String Client_failed_exchange_combo_token = "[Dispatch] Client %s failed to exchange combo token"; + public String Dispatch_start_server_port = "[Dispatch] Dispatch server started on port %s"; + public String Client_failed_login_account_create = "[Dispatch] Client %s failed to log in: Account %s created"; + public String Client_failed_login_account_create_failed = "[Dispatch] Client %s failed to log in: Account create failed"; + public String Client_failed_login_account_no_found = "[Dispatch] Client %s failed to log in: Account no found"; + public String Client_login = "[Dispatch] Client %s logged in as %s"; + public String Username_not_found = "Username not found."; + public String Username_not_found_create_failed = "Username not found, create failed."; + + // Command + public String No_command_specified = "No command specified."; + public String Unknown_command = "Unknown command: "; + public String You_not_permission_run_command = "You do not have permission to run this command."; + public String This_command_can_only_run_from_console = "This command can only be run from the console."; + public String Run_this_command_in_game = "Run this command in-game."; + public String Invalid_playerId = "Invalid playerId."; + public String Player_not_found = "Player not found."; + public String Player_is_offline = "Player is offline."; + public String Invalid_item_id = "Invalid item id."; + public String Invalid_item_or_player_id = "Invalid item or player ID."; + public String Enabled = "enabled"; + public String Disabled = "disabled"; + public String No_command_found = "No command found."; + public String Help = "Help"; + public String Player_not_found_or_offline = "Player not found or offline."; + public String Invalid_arguments = "Invalid arguments."; + public String Success = "Success"; + public String Invalid_entity_id = "Invalid entity id."; + + // Help + public String Help_usage = " Usage: "; + public String Help_aliases = " Aliases: "; + public String Help_available_command = "Available commands:"; + + // Account + public String Modify_user_account = "Modify user accounts"; + public String Invalid_UID = "Invalid UID."; + public String Account_exists = "Account already exists."; + public String Account_create_UID = "Account created with UID %s."; + public String Account_delete = "Account deleted."; + public String Account_not_find = "Account not found."; + public String Account_command_usage = "Usage: account [uid]"; + + // Broadcast + public String Broadcast_command_usage = "Usage: broadcast "; + public String Broadcast_message_sent = "Message sent."; + + // ChangeScene + public String Change_screen_usage = "Usage: changescene "; + public String Change_screen_you_in_that_screen = "You are already in that scene"; + public String Change_screen = "Changed to scene "; + public String Change_screen_not_exist = "Scene does not exist"; + + // Clear + public String Clear_weapons = "Cleared weapons for %s ."; + public String Clear_artifacts = "Cleared artifacts for %s ."; + public String Clear_materials = "Cleared materials for %s ."; + public String Clear_furniture = "Cleared furniture for %s ."; + public String Clear_displays = "Cleared displays for %s ."; + public String Clear_virtuals = "Cleared virtuals for %s ."; + public String Clear_everything = "Cleared everything for %s ."; + + // Coop + public String Coop_usage = "Usage: coop "; + + // Drop + public String Drop_usage = "Usage: drop [amount]"; + public String Drop_dropped_of = "Dropped %s of %s."; + + // EnterDungeon + public String EnterDungeon_usage = "Usage: enterdungeon "; + public String EnterDungeon_changed_to_dungeon = "Changed to dungeon "; + public String EnterDungeon_dungeon_not_found = "Dungeon does not exist"; + public String EnterDungeon_you_in_that_dungeon = "You are already in that dungeon"; + + // GiveAll + public String GiveAll_usage = "Usage: giveall [player] [amount]"; + public String GiveAll_item = "Giving all items..."; + public String GiveAll_done = "Giving all items done"; + public String GiveAll_invalid_amount_or_playerId = "Invalid amount or player ID."; + + // GiveArtifact + public String GiveArtifact_usage = "Usage: giveart|gart [player] [[,]]... [level]"; + public String GiveArtifact_invalid_artifact_id = "Invalid artifact ID."; + public String GiveArtifact_given = "Given %s to %s."; + + // GiveChar + public String GiveChar_usage = "Usage: givechar [amount]"; + public String GiveChar_given = "Given %s with level %s to %s."; + public String GiveChar_invalid_avatar_id = "Invalid avatar id."; + public String GiveChar_invalid_avatar_level = "Invalid avatar level."; + public String GiveChar_invalid_avatar_or_player_id = "Invalid avatar or player ID."; + + // Give + public String Give_usage = "Usage: give [amount] [level]"; + public String Give_refinement_only_applicable_weapons = "Refinement is only applicable to weapons."; + public String Give_refinement_must_between_1_and_5 = "Refinement must be between 1 and 5."; + public String Give_given = "Given %s of %s to %s."; + public String Give_given_with_level_and_refinement = "Given %s with level %s, refinement %s %s times to %s"; + public String Give_given_level = "Given %s with level %s %s times to %s"; + + // GodMode + public String Godmode_status = "Godmode is now %s for %s ."; + + // Heal + public String Heal_message = "All characters have been healed."; + + // Kick + public String Kick_player_kick_player = "Player [%s:%s] has kicked player [%s:%s]"; + public String Kick_server_player = "Kicking player [%s:%s]"; + + // Kill + public String Kill_usage = "Usage: killall [playerUid] [sceneId]"; + public String Kill_scene_not_found_in_player_world = "Scene not found in player world"; + public String Kill_kill_monsters_in_scene = "Killing %s monsters in scene %s"; + + // KillCharacter + public String KillCharacter_usage = "Usage: /killcharacter [playerId]"; + public String KillCharacter_kill_current_character = "Killed %s current character."; + + // List + public String List_message = "There are %s player(s) online:"; + + // Permission + public String Permission_usage = "Usage: permission "; + public String Permission_add = "Permission added."; + public String Permission_have_permission = "They already have this permission!"; + public String Permission_remove = "Permission removed."; + public String Permission_not_have_permission = "They don't have this permission!"; + + // Position + public String Position_message = "Coord: %.3f, %.3f, %.3f\nScene id: %d"; + + // Reload + public String Reload_reload_start = "Reloading config."; + public String Reload_reload_done = "Reload complete."; + + // ResetConst + public String ResetConst_reset_all = "Reset all avatars' constellations."; + public String ResetConst_reset_all_done = "Constellations for %s have been reset. Please relog to see changes."; + + // ResetShopLimit + public String ResetShopLimit_usage = "Usage: /resetshop "; + + // SendMail + public String SendMail_usage = "Usage: give [player] [amount]"; + public String SendMail_user_not_exist = "The user with an id of '%s' does not exist"; + public String SendMail_start_composition = "Starting composition of message.\nPlease use `/sendmail ` to continue.\nYou can use `/sendmail stop` at any time"; + public String SendMail_templates = "Mail templates coming soon implemented..."; + public String SendMail_invalid_arguments = "Invalid arguments.\nUsage `/sendmail <userId|all|help> [templateId]`"; + public String SendMail_send_cancel = "Message sending cancelled"; + public String SendMail_send_done = "Message sent to user %s!"; + public String SendMail_send_all_done = "Message sent to all users!"; + public String SendMail_not_composition_end = "Message composition not at final stage.\nPlease use `/sendmail %s` or `/sendmail stop` to cancel"; + public String SendMail_Please_use = "Please use `/sendmail %s`"; + public String SendMail_set_title = "Message title set as '%s'.\nUse '/sendmail <content>' to continue."; + public String SendMail_set_contents = "Message contents set as '%s'.\nUse '/sendmail <sender>' to continue."; + public String SendMail_set_message_sender = "Message sender set as '%s'.\nUse '/sendmail <itemId|itemName|finish> [amount] [level]' to continue."; + public String SendMail_send = "Attached %s of %s (level %s) to the message.\nContinue adding more items or use `/sendmail finish` to send the message."; + public String SendMail_invalid_arguments_please_use = "Invalid arguments \n Please use `/sendmail %s`"; + public String SendMail_title = "<title>"; + public String SendMail_message = "<message>"; + public String SendMail_sender = "<sender>"; + public String SendMail_arguments = "<itemId|itemName|finish> [amount] [level]"; + public String SendMail_error = "ERROR: invalid construction stage %s. Check console for stacktrace."; + + // SendMessage + public String SendMessage_usage = "Usage: sendmessage <player> <message>"; + public String SenaMessage_message_sent = "Message sent."; + + // SetFetterLevel + public String SetFetterLevel_usage = "Usage: setfetterlevel <level>"; + public String SetFetterLevel_fetter_level_must_between_0_and_10 = "Fetter level must be between 0 and 10."; + public String SetFetterLevel_fetter_set_level = "Fetter level set to %s"; + public String SetFetterLevel_invalid_fetter_level = "Invalid fetter level."; + + // SetStats + public String SetStats_usage = "Usage: setstats|stats <stat> <value>"; + public String SetStats_setstats_help_message = "Usage: /setstats|stats <hp | mhp | def | atk | em | er | crate | cdmg> <value> for basic stats"; + public String SetStats_stats_help_message = "Usage: /stats <epyro | ecryo | ehydro | egeo | edend | eelec | ephys> <amount> for elemental bonus"; + public String SetStats_set_max_hp = "MAX HP set to %s."; + public String SetStats_set_max_hp_error = "Invalid Max HP value."; + public String SetStats_set_hp = "HP set to %s."; + public String SetStats_set_hp_error = "Invalid HP value."; + public String SetStats_set_def = "DEF set to %s."; + public String SetStats_set_def_error = "Invalid DEF value."; + public String SetStats_set_atk = "ATK set to %s."; + public String SetStats_set_atk_error = "Invalid ATK value."; + public String SetStats_set_em = "Elemental Mastery set to %s."; + public String SetStats_set_em_error = "Invalid EM value."; + public String SetStats_set_er = "Energy recharge set to %s%."; + public String SetStats_set_er_error = "Invalid ER value."; + public String SetStats_set_cr = "Crit Rate set to %s%."; + public String SetStats_set_cr_error = "Invalid Crit Rate value."; + public String SetStats_set_cd = "Crit DMG set to %s%."; + public String SetStats_set_cd_error = "Invalid Crit DMG value."; + public String SetStats_set_pdb = "Pyro DMG Bonus set to %s%."; + public String SetStats_set_pdb_error = "Invalid Pyro DMG Bonus value."; + public String SetStats_set_cdb = "Cyro DMG Bonus set to %s%."; + public String SetStats_set_cdb_error = "Invalid Cyro DMG Bonus value."; + public String SetStats_set_hdb = "Hydro DMG Bonus set to %s%."; + public String SetStats_set_hdb_error = "Invalid Hydro DMG Bonus value."; + public String SetStats_set_adb = "Anemo DMG Bonus set to %s%."; + public String SetStats_set_adb_error = "Invalid Anemo DMG Bonus value."; + public String SetStats_set_gdb = "Geo DMG Bonus set to %s%."; + public String SetStats_set_gdb_error = "Invalid Geo DMG Bonus value."; + public String SetStats_set_edb = "Electro DMG Bonus set to %s%."; + public String SetStats_set_edb_error = "Invalid Electro DMG Bonus value."; + public String SetStats_set_physdb = "Physical DMG Bonus set to %s%."; + public String SetStats_set_physdb_error = "Invalid Physical DMG Bonus value."; + public String SetStats_set_ddb = "Dendro DMG Bonus set to %s%."; + public String SetStats_set_ddb_error = "Invalid Dendro DMG Bonus value."; + + // SetWorldLevel + public String SetWorldLevel_usage = "Usage: setworldlevel <level>"; + public String SetWorldLevel_world_level_must_between_0_and_8 = "World level must be between 0-8"; + public String SetWorldLevel_set_world_level = "World level set to %s."; + public String SetWorldLevel_invalid_world_level = "Invalid world level."; + + // Spawn + public String Spawn_usage = "Usage: spawn <entityId> [amount] [level(monster only)]"; + public String Spawn_message = "Spawned %s of %s."; + + // Stop + public String Stop_message = "Server shutting down..."; + + // Talent + public String Talent_usage_1 = "To set talent level: /talent set <talentID> <value>"; + public String Talent_usage_2 = "Another way to set talent level: /talent <n or e or q> <value>"; + public String Talent_usage_3 = "To get talent ID: /talent getid"; + public String Talent_lower_16 = "Invalid talent level. Level should be lower than 16"; + public String Talent_set_atk = "Set talent Normal ATK to %s."; + public String Talent_set_e = "Set talent E to %s."; + public String Talent_set_q = "Set talent Q to %s."; + public String Talent_invalid_skill_id = "Invalid skill ID."; + public String Talent_set_this = "Set this talent to %s."; + public String Talent_invalid_talent_level = "Invalid talent level."; + public String Talent_normal_attack_id = "Normal Attack ID %s."; + public String Talent_e_skill_id = "E skill ID %s."; + public String Talent_q_skill_id = "Q skill ID %s."; + + // TeleportAll + public String TeleportAll_message = "You only can use this command in MP mode."; + + // Teleport + public String Teleport_usage_server = "Usage: /tp @<player id> <x> <y> <z> [scene id]"; + public String Teleport_usage = "Usage: /tp [@<player id>] <x> <y> <z> [scene id]"; + public String Teleport_specify_player_id = "You must specify a player id."; + public String Teleport_invalid_position = "Invalid position."; + public String Teleport_message = "Teleported %s to %s,%s,%s in scene %s"; + + // Weather + public String Weather_usage = "Usage: weather <weatherId> [climateId]"; + public String Weather_message = "Changed weather to %s with climate %s"; + public String Weather_invalid_id = "Invalid ID."; +} diff --git a/src/main/java/emu/grasscutter/server/dispatch/DispatchServer.java b/src/main/java/emu/grasscutter/server/dispatch/DispatchServer.java index 196faf880..85f02a36d 100644 --- a/src/main/java/emu/grasscutter/server/dispatch/DispatchServer.java +++ b/src/main/java/emu/grasscutter/server/dispatch/DispatchServer.java @@ -16,14 +16,16 @@ import emu.grasscutter.net.proto.RegionInfoOuterClass.RegionInfo; import emu.grasscutter.net.proto.RegionSimpleInfoOuterClass.RegionSimpleInfo; import emu.grasscutter.server.dispatch.authentication.AuthenticationHandler; import emu.grasscutter.server.dispatch.authentication.DefaultAuthenticationHandler; +import emu.grasscutter.server.dispatch.http.GachaRecordHandler; import emu.grasscutter.server.dispatch.json.*; import emu.grasscutter.server.dispatch.json.ComboTokenReqJson.LoginTokenData; import emu.grasscutter.server.event.dispatch.QueryAllRegionsEvent; import emu.grasscutter.server.event.dispatch.QueryCurrentRegionEvent; -import emu.grasscutter.server.http.gacha.GachaRecordHandler; -import emu.grasscutter.server.http.gcstatic.StaticFileHandler; +import emu.grasscutter.tools.Tools; import emu.grasscutter.utils.FileUtils; +import emu.grasscutter.utils.Utils; import express.Express; +import io.javalin.http.staticfiles.Location; import org.eclipse.jetty.server.Connector; import org.eclipse.jetty.server.Server; import org.eclipse.jetty.server.ServerConnector; @@ -442,11 +444,18 @@ public final class DispatchServer { // webstatic-sea.hoyoverse.com httpServer.get("/admin/mi18n/plat_oversea/m202003048/m202003048-version.json", new DispatchHttpJsonHandler("{\"version\":51}")); - // gacha record + // gacha record. + String gachaMappingsPath = Utils.toFilePath(Grasscutter.getConfig().DATA_FOLDER + "/gacha_mappings.js"); + // TODO: Only serve the html page and have a subsequent request to fetch the gacha data. httpServer.get("/gacha", new GachaRecordHandler()); + if(!(new File(gachaMappingsPath).exists())) { + Tools.createGachaMapping(gachaMappingsPath); + } - // static file provider - httpServer.get("/gcstatic/*", new StaticFileHandler()); + httpServer.raw().config.addSinglePageRoot("/gacha/mappings", gachaMappingsPath, Location.EXTERNAL); + + // static file support for plugins + httpServer.raw().config.precompressStaticFiles = false; // If this isn't set to false, files such as images may appear corrupted when serving static files httpServer.listen(Grasscutter.getConfig().getDispatchOptions().Port); Grasscutter.getLogger().info(Grasscutter.getLanguage().Dispatch_start_server_port.replace("{port}", Integer.toString(httpServer.raw().port()))); diff --git a/src/main/java/emu/grasscutter/server/http/gacha/GachaRecordHandler.java b/src/main/java/emu/grasscutter/server/dispatch/http/GachaRecordHandler.java similarity index 88% rename from src/main/java/emu/grasscutter/server/http/gacha/GachaRecordHandler.java rename to src/main/java/emu/grasscutter/server/dispatch/http/GachaRecordHandler.java index 0798a150f..8ca47976e 100644 --- a/src/main/java/emu/grasscutter/server/http/gacha/GachaRecordHandler.java +++ b/src/main/java/emu/grasscutter/server/dispatch/http/GachaRecordHandler.java @@ -1,4 +1,4 @@ -package emu.grasscutter.server.http.gacha; +package emu.grasscutter.server.dispatch.http; import java.io.File; import java.io.IOException; @@ -7,6 +7,7 @@ import emu.grasscutter.Grasscutter; import emu.grasscutter.database.DatabaseHelper; import emu.grasscutter.game.Account; import emu.grasscutter.utils.FileUtils; +import emu.grasscutter.utils.Utils; import express.http.HttpContextHandler; import express.http.Request; import express.http.Response; @@ -14,7 +15,7 @@ import express.http.Response; public final class GachaRecordHandler implements HttpContextHandler { String render_template; public GachaRecordHandler() { - File template = new File(Grasscutter.getConfig().DATA_FOLDER + "gacha_records.html"); + File template = new File(Utils.toFilePath(Grasscutter.getConfig().DATA_FOLDER + "/gacha_records.html")); if (template.exists()) { // Load from cache render_template = new String(FileUtils.read(template)); diff --git a/src/main/java/emu/grasscutter/server/http/gcstatic/StaticFileHandler.java b/src/main/java/emu/grasscutter/server/http/gcstatic/StaticFileHandler.java deleted file mode 100644 index 0cdccb2c1..000000000 --- a/src/main/java/emu/grasscutter/server/http/gcstatic/StaticFileHandler.java +++ /dev/null @@ -1,31 +0,0 @@ -package emu.grasscutter.server.http.gcstatic; - -import java.io.File; -import java.io.IOException; - -import emu.grasscutter.Grasscutter; -import express.http.HttpContextHandler; -import express.http.Request; -import express.http.Response; - -public final class StaticFileHandler implements HttpContextHandler { - String static_folder; - public StaticFileHandler() { - static_folder = Grasscutter.getConfig().RESOURCE_FOLDER + "/gcstatic"; - } - - @Override - public void handle(Request req, Response res) throws IOException { - // Grasscutter.getLogger().info( req.path()); - - String reqFilename = req.path().replace("/gcstatic", ""); // remove the leading path - reqFilename = reqFilename.replace("/../", "/./"); // security guard to prevent arbitrary read - File resFile = new File(static_folder + reqFilename); - if (resFile.exists()) { - res.sendFile(resFile.toPath()); - } else { - res.status(404); - res.send("404"); - } - } -} diff --git a/src/main/java/emu/grasscutter/tools/Tools.java b/src/main/java/emu/grasscutter/tools/Tools.java index d7f5e986a..c4ccd2d2e 100644 --- a/src/main/java/emu/grasscutter/tools/Tools.java +++ b/src/main/java/emu/grasscutter/tools/Tools.java @@ -96,7 +96,7 @@ public final class Tools { } @SuppressWarnings("deprecation") - public static void createGachaMapping() throws Exception { + public static void createGachaMapping(String location) throws Exception { ResourceLoader.loadResources(); Map<Long, String> map; @@ -106,11 +106,7 @@ public final class Tools { List<Integer> list; - - String fileName = Grasscutter.getConfig().RESOURCE_FOLDER + "/gcstatic"; - File folder = new File(fileName); - if (!folder.exists()) { folder.mkdirs(); } // create folder if it doesn't exist - fileName = fileName + "/mappings.js"; + String fileName = location; try (PrintWriter writer = new PrintWriter(new OutputStreamWriter(new FileOutputStream(fileName), StandardCharsets.UTF_8), false)) { From db1ddd0630d156483d8320c194f87e5802939b09 Mon Sep 17 00:00:00 2001 From: Benjamin Elsdon <benjamin7006@gmail.com> Date: Thu, 5 May 2022 19:20:18 +0800 Subject: [PATCH 03/11] I honestly don't know what happened.... --- src/main/java/emu/grasscutter/Language.java | 285 -------------------- 1 file changed, 285 deletions(-) delete mode 100644 src/main/java/emu/grasscutter/Language.java diff --git a/src/main/java/emu/grasscutter/Language.java b/src/main/java/emu/grasscutter/Language.java deleted file mode 100644 index e5150a6fe..000000000 --- a/src/main/java/emu/grasscutter/Language.java +++ /dev/null @@ -1,285 +0,0 @@ -package emu.grasscutter; - -public final class Language { - public String An_error_occurred_during_game_update = "An error occurred during game update."; - public String Starting_Grasscutter = "Starting Grasscutter..."; - public String Invalid_server_run_mode = "Invalid server run mode."; - public String Server_run_mode = "Server run mode must be 'HYBRID', 'DISPATCH_ONLY', or 'GAME_ONLY'. Unable to start Grasscutter..."; - public String Shutting_down = "Shutting down..."; - public String Start_done = "Done! For help, type \"help\""; - public String Dispatch_mode_not_support_command = "Commands are not supported in dispatch only mode."; - public String Command_error = "Command error:"; - public String error = "An error occurred."; - public String grasscutter_is_free = "Grasscutter is FREE software. If you have paid for this, you may have been scammed. Homepage: https://github.com/Grasscutters/Grasscutter"; - public String Game_start_port = "Game Server started on port %s"; - public String Client_connect = "Client connected from %s"; - public String Client_disconnect = "Client disconnected from %s"; - public String Client_request = "[Dispatch] Client %s %s request: %s"; - public String Not_load_keystore = "[Dispatch] Unable to load keystore. Trying default keystore password..."; - public String Use_default_keystore = "[Dispatch] The default keystore password was loaded successfully. Please consider setting the password to 123456 in config.json."; - public String Load_keystore_error = "[Dispatch] Error while loading keystore!"; - public String Not_find_ssl_cert = "[Dispatch] No SSL cert found! Falling back to HTTP server."; - public String Welcome = "Welcome to Grasscutter"; - public String Potential_unhandled_request = "[Dispatch] Potential unhandled %s request: %s"; - public String Client_login_token = "[Dispatch] Client %s is trying to log in via token"; - public String Client_token_login_failed = "[Dispatch] Client %s failed to log in via token"; - public String Client_login_in_token = "[Dispatch] Client %s logged in via token as %s"; - public String Game_account_cache_error = "Game account cache information error"; - public String Wrong_session_key = "Wrong session key."; - public String Client_exchange_combo_token = "[Dispatch] Client %s succeed to exchange combo token"; - public String Client_failed_exchange_combo_token = "[Dispatch] Client %s failed to exchange combo token"; - public String Dispatch_start_server_port = "[Dispatch] Dispatch server started on port %s"; - public String Client_failed_login_account_create = "[Dispatch] Client %s failed to log in: Account %s created"; - public String Client_failed_login_account_create_failed = "[Dispatch] Client %s failed to log in: Account create failed"; - public String Client_failed_login_account_no_found = "[Dispatch] Client %s failed to log in: Account no found"; - public String Client_login = "[Dispatch] Client %s logged in as %s"; - public String Username_not_found = "Username not found."; - public String Username_not_found_create_failed = "Username not found, create failed."; - - // Command - public String No_command_specified = "No command specified."; - public String Unknown_command = "Unknown command: "; - public String You_not_permission_run_command = "You do not have permission to run this command."; - public String This_command_can_only_run_from_console = "This command can only be run from the console."; - public String Run_this_command_in_game = "Run this command in-game."; - public String Invalid_playerId = "Invalid playerId."; - public String Player_not_found = "Player not found."; - public String Player_is_offline = "Player is offline."; - public String Invalid_item_id = "Invalid item id."; - public String Invalid_item_or_player_id = "Invalid item or player ID."; - public String Enabled = "enabled"; - public String Disabled = "disabled"; - public String No_command_found = "No command found."; - public String Help = "Help"; - public String Player_not_found_or_offline = "Player not found or offline."; - public String Invalid_arguments = "Invalid arguments."; - public String Success = "Success"; - public String Invalid_entity_id = "Invalid entity id."; - - // Help - public String Help_usage = " Usage: "; - public String Help_aliases = " Aliases: "; - public String Help_available_command = "Available commands:"; - - // Account - public String Modify_user_account = "Modify user accounts"; - public String Invalid_UID = "Invalid UID."; - public String Account_exists = "Account already exists."; - public String Account_create_UID = "Account created with UID %s."; - public String Account_delete = "Account deleted."; - public String Account_not_find = "Account not found."; - public String Account_command_usage = "Usage: account <create|delete> <username> [uid]"; - - // Broadcast - public String Broadcast_command_usage = "Usage: broadcast <message>"; - public String Broadcast_message_sent = "Message sent."; - - // ChangeScene - public String Change_screen_usage = "Usage: changescene <scene id>"; - public String Change_screen_you_in_that_screen = "You are already in that scene"; - public String Change_screen = "Changed to scene "; - public String Change_screen_not_exist = "Scene does not exist"; - - // Clear - public String Clear_weapons = "Cleared weapons for %s ."; - public String Clear_artifacts = "Cleared artifacts for %s ."; - public String Clear_materials = "Cleared materials for %s ."; - public String Clear_furniture = "Cleared furniture for %s ."; - public String Clear_displays = "Cleared displays for %s ."; - public String Clear_virtuals = "Cleared virtuals for %s ."; - public String Clear_everything = "Cleared everything for %s ."; - - // Coop - public String Coop_usage = "Usage: coop <playerId> <target playerId>"; - - // Drop - public String Drop_usage = "Usage: drop <itemId|itemName> [amount]"; - public String Drop_dropped_of = "Dropped %s of %s."; - - // EnterDungeon - public String EnterDungeon_usage = "Usage: enterdungeon <dungeon id>"; - public String EnterDungeon_changed_to_dungeon = "Changed to dungeon "; - public String EnterDungeon_dungeon_not_found = "Dungeon does not exist"; - public String EnterDungeon_you_in_that_dungeon = "You are already in that dungeon"; - - // GiveAll - public String GiveAll_usage = "Usage: giveall [player] [amount]"; - public String GiveAll_item = "Giving all items..."; - public String GiveAll_done = "Giving all items done"; - public String GiveAll_invalid_amount_or_playerId = "Invalid amount or player ID."; - - // GiveArtifact - public String GiveArtifact_usage = "Usage: giveart|gart [player] <artifactId> <mainPropId> [<appendPropId>[,<times>]]... [level]"; - public String GiveArtifact_invalid_artifact_id = "Invalid artifact ID."; - public String GiveArtifact_given = "Given %s to %s."; - - // GiveChar - public String GiveChar_usage = "Usage: givechar <player> <itemId|itemName> [amount]"; - public String GiveChar_given = "Given %s with level %s to %s."; - public String GiveChar_invalid_avatar_id = "Invalid avatar id."; - public String GiveChar_invalid_avatar_level = "Invalid avatar level."; - public String GiveChar_invalid_avatar_or_player_id = "Invalid avatar or player ID."; - - // Give - public String Give_usage = "Usage: give <player> <itemId|itemName> [amount] [level]"; - public String Give_refinement_only_applicable_weapons = "Refinement is only applicable to weapons."; - public String Give_refinement_must_between_1_and_5 = "Refinement must be between 1 and 5."; - public String Give_given = "Given %s of %s to %s."; - public String Give_given_with_level_and_refinement = "Given %s with level %s, refinement %s %s times to %s"; - public String Give_given_level = "Given %s with level %s %s times to %s"; - - // GodMode - public String Godmode_status = "Godmode is now %s for %s ."; - - // Heal - public String Heal_message = "All characters have been healed."; - - // Kick - public String Kick_player_kick_player = "Player [%s:%s] has kicked player [%s:%s]"; - public String Kick_server_player = "Kicking player [%s:%s]"; - - // Kill - public String Kill_usage = "Usage: killall [playerUid] [sceneId]"; - public String Kill_scene_not_found_in_player_world = "Scene not found in player world"; - public String Kill_kill_monsters_in_scene = "Killing %s monsters in scene %s"; - - // KillCharacter - public String KillCharacter_usage = "Usage: /killcharacter [playerId]"; - public String KillCharacter_kill_current_character = "Killed %s current character."; - - // List - public String List_message = "There are %s player(s) online:"; - - // Permission - public String Permission_usage = "Usage: permission <add|remove> <username> <permission>"; - public String Permission_add = "Permission added."; - public String Permission_have_permission = "They already have this permission!"; - public String Permission_remove = "Permission removed."; - public String Permission_not_have_permission = "They don't have this permission!"; - - // Position - public String Position_message = "Coord: %.3f, %.3f, %.3f\nScene id: %d"; - - // Reload - public String Reload_reload_start = "Reloading config."; - public String Reload_reload_done = "Reload complete."; - - // ResetConst - public String ResetConst_reset_all = "Reset all avatars' constellations."; - public String ResetConst_reset_all_done = "Constellations for %s have been reset. Please relog to see changes."; - - // ResetShopLimit - public String ResetShopLimit_usage = "Usage: /resetshop <player id>"; - - // SendMail - public String SendMail_usage = "Usage: give [player] <itemId|itemName> [amount]"; - public String SendMail_user_not_exist = "The user with an id of '%s' does not exist"; - public String SendMail_start_composition = "Starting composition of message.\nPlease use `/sendmail <title>` to continue.\nYou can use `/sendmail stop` at any time"; - public String SendMail_templates = "Mail templates coming soon implemented..."; - public String SendMail_invalid_arguments = "Invalid arguments.\nUsage `/sendmail <userId|all|help> [templateId]`"; - public String SendMail_send_cancel = "Message sending cancelled"; - public String SendMail_send_done = "Message sent to user %s!"; - public String SendMail_send_all_done = "Message sent to all users!"; - public String SendMail_not_composition_end = "Message composition not at final stage.\nPlease use `/sendmail %s` or `/sendmail stop` to cancel"; - public String SendMail_Please_use = "Please use `/sendmail %s`"; - public String SendMail_set_title = "Message title set as '%s'.\nUse '/sendmail <content>' to continue."; - public String SendMail_set_contents = "Message contents set as '%s'.\nUse '/sendmail <sender>' to continue."; - public String SendMail_set_message_sender = "Message sender set as '%s'.\nUse '/sendmail <itemId|itemName|finish> [amount] [level]' to continue."; - public String SendMail_send = "Attached %s of %s (level %s) to the message.\nContinue adding more items or use `/sendmail finish` to send the message."; - public String SendMail_invalid_arguments_please_use = "Invalid arguments \n Please use `/sendmail %s`"; - public String SendMail_title = "<title>"; - public String SendMail_message = "<message>"; - public String SendMail_sender = "<sender>"; - public String SendMail_arguments = "<itemId|itemName|finish> [amount] [level]"; - public String SendMail_error = "ERROR: invalid construction stage %s. Check console for stacktrace."; - - // SendMessage - public String SendMessage_usage = "Usage: sendmessage <player> <message>"; - public String SenaMessage_message_sent = "Message sent."; - - // SetFetterLevel - public String SetFetterLevel_usage = "Usage: setfetterlevel <level>"; - public String SetFetterLevel_fetter_level_must_between_0_and_10 = "Fetter level must be between 0 and 10."; - public String SetFetterLevel_fetter_set_level = "Fetter level set to %s"; - public String SetFetterLevel_invalid_fetter_level = "Invalid fetter level."; - - // SetStats - public String SetStats_usage = "Usage: setstats|stats <stat> <value>"; - public String SetStats_setstats_help_message = "Usage: /setstats|stats <hp | mhp | def | atk | em | er | crate | cdmg> <value> for basic stats"; - public String SetStats_stats_help_message = "Usage: /stats <epyro | ecryo | ehydro | egeo | edend | eelec | ephys> <amount> for elemental bonus"; - public String SetStats_set_max_hp = "MAX HP set to %s."; - public String SetStats_set_max_hp_error = "Invalid Max HP value."; - public String SetStats_set_hp = "HP set to %s."; - public String SetStats_set_hp_error = "Invalid HP value."; - public String SetStats_set_def = "DEF set to %s."; - public String SetStats_set_def_error = "Invalid DEF value."; - public String SetStats_set_atk = "ATK set to %s."; - public String SetStats_set_atk_error = "Invalid ATK value."; - public String SetStats_set_em = "Elemental Mastery set to %s."; - public String SetStats_set_em_error = "Invalid EM value."; - public String SetStats_set_er = "Energy recharge set to %s%."; - public String SetStats_set_er_error = "Invalid ER value."; - public String SetStats_set_cr = "Crit Rate set to %s%."; - public String SetStats_set_cr_error = "Invalid Crit Rate value."; - public String SetStats_set_cd = "Crit DMG set to %s%."; - public String SetStats_set_cd_error = "Invalid Crit DMG value."; - public String SetStats_set_pdb = "Pyro DMG Bonus set to %s%."; - public String SetStats_set_pdb_error = "Invalid Pyro DMG Bonus value."; - public String SetStats_set_cdb = "Cyro DMG Bonus set to %s%."; - public String SetStats_set_cdb_error = "Invalid Cyro DMG Bonus value."; - public String SetStats_set_hdb = "Hydro DMG Bonus set to %s%."; - public String SetStats_set_hdb_error = "Invalid Hydro DMG Bonus value."; - public String SetStats_set_adb = "Anemo DMG Bonus set to %s%."; - public String SetStats_set_adb_error = "Invalid Anemo DMG Bonus value."; - public String SetStats_set_gdb = "Geo DMG Bonus set to %s%."; - public String SetStats_set_gdb_error = "Invalid Geo DMG Bonus value."; - public String SetStats_set_edb = "Electro DMG Bonus set to %s%."; - public String SetStats_set_edb_error = "Invalid Electro DMG Bonus value."; - public String SetStats_set_physdb = "Physical DMG Bonus set to %s%."; - public String SetStats_set_physdb_error = "Invalid Physical DMG Bonus value."; - public String SetStats_set_ddb = "Dendro DMG Bonus set to %s%."; - public String SetStats_set_ddb_error = "Invalid Dendro DMG Bonus value."; - - // SetWorldLevel - public String SetWorldLevel_usage = "Usage: setworldlevel <level>"; - public String SetWorldLevel_world_level_must_between_0_and_8 = "World level must be between 0-8"; - public String SetWorldLevel_set_world_level = "World level set to %s."; - public String SetWorldLevel_invalid_world_level = "Invalid world level."; - - // Spawn - public String Spawn_usage = "Usage: spawn <entityId> [amount] [level(monster only)]"; - public String Spawn_message = "Spawned %s of %s."; - - // Stop - public String Stop_message = "Server shutting down..."; - - // Talent - public String Talent_usage_1 = "To set talent level: /talent set <talentID> <value>"; - public String Talent_usage_2 = "Another way to set talent level: /talent <n or e or q> <value>"; - public String Talent_usage_3 = "To get talent ID: /talent getid"; - public String Talent_lower_16 = "Invalid talent level. Level should be lower than 16"; - public String Talent_set_atk = "Set talent Normal ATK to %s."; - public String Talent_set_e = "Set talent E to %s."; - public String Talent_set_q = "Set talent Q to %s."; - public String Talent_invalid_skill_id = "Invalid skill ID."; - public String Talent_set_this = "Set this talent to %s."; - public String Talent_invalid_talent_level = "Invalid talent level."; - public String Talent_normal_attack_id = "Normal Attack ID %s."; - public String Talent_e_skill_id = "E skill ID %s."; - public String Talent_q_skill_id = "Q skill ID %s."; - - // TeleportAll - public String TeleportAll_message = "You only can use this command in MP mode."; - - // Teleport - public String Teleport_usage_server = "Usage: /tp @<player id> <x> <y> <z> [scene id]"; - public String Teleport_usage = "Usage: /tp [@<player id>] <x> <y> <z> [scene id]"; - public String Teleport_specify_player_id = "You must specify a player id."; - public String Teleport_invalid_position = "Invalid position."; - public String Teleport_message = "Teleported %s to %s,%s,%s in scene %s"; - - // Weather - public String Weather_usage = "Usage: weather <weatherId> [climateId]"; - public String Weather_message = "Changed weather to %s with climate %s"; - public String Weather_invalid_id = "Invalid ID."; -} From 782c9bfb6b784a061ad7099278dadea2855beee1 Mon Sep 17 00:00:00 2001 From: Benjamin Elsdon <benjamin7006@gmail.com> Date: Thu, 5 May 2022 19:38:05 +0800 Subject: [PATCH 04/11] No misleading 404 error --- .../grasscutter/server/dispatch/http/GachaRecordHandler.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/emu/grasscutter/server/dispatch/http/GachaRecordHandler.java b/src/main/java/emu/grasscutter/server/dispatch/http/GachaRecordHandler.java index 8ca47976e..8676574bb 100644 --- a/src/main/java/emu/grasscutter/server/dispatch/http/GachaRecordHandler.java +++ b/src/main/java/emu/grasscutter/server/dispatch/http/GachaRecordHandler.java @@ -47,7 +47,7 @@ public final class GachaRecordHandler implements HttpContextHandler { res.send(response); } else { - res.send("404"); + res.send("No account found."); } } } From 3f34aa04605ce77e87bfdd85cd6baa0a6c9f723b Mon Sep 17 00:00:00 2001 From: Akka <104902222+Akka0@users.noreply.github.com> Date: Thu, 5 May 2022 22:00:11 +0800 Subject: [PATCH 05/11] Support of Enter Room Scene --- .../grasscutter/data/common/PointData.java | 11 +++++- .../recv/HandlerPersonalSceneJumpReq.java | 38 +++++++++++++++++++ .../send/PacketPersonalSceneJumpRsp.java | 20 ++++++++++ 3 files changed, 68 insertions(+), 1 deletion(-) create mode 100644 src/main/java/emu/grasscutter/server/packet/recv/HandlerPersonalSceneJumpReq.java create mode 100644 src/main/java/emu/grasscutter/server/packet/send/PacketPersonalSceneJumpRsp.java diff --git a/src/main/java/emu/grasscutter/data/common/PointData.java b/src/main/java/emu/grasscutter/data/common/PointData.java index fa3891d7c..492f1fc60 100644 --- a/src/main/java/emu/grasscutter/data/common/PointData.java +++ b/src/main/java/emu/grasscutter/data/common/PointData.java @@ -13,7 +13,8 @@ public class PointData { private Position tranPos; private int[] dungeonIds; private int[] dungeonRandomList; - + + private int tranSceneId; public int getId() { return id; } @@ -38,6 +39,14 @@ public class PointData { return dungeonRandomList; } + public int getTranSceneId() { + return tranSceneId; + } + + public void setTranSceneId(int tranSceneId) { + this.tranSceneId = tranSceneId; + } + public void updateDailyDungeon() { if (getDungeonRandomList() == null) { return; diff --git a/src/main/java/emu/grasscutter/server/packet/recv/HandlerPersonalSceneJumpReq.java b/src/main/java/emu/grasscutter/server/packet/recv/HandlerPersonalSceneJumpReq.java new file mode 100644 index 000000000..98c6984ee --- /dev/null +++ b/src/main/java/emu/grasscutter/server/packet/recv/HandlerPersonalSceneJumpReq.java @@ -0,0 +1,38 @@ +package emu.grasscutter.server.packet.recv; + +import emu.grasscutter.data.GameData; +import emu.grasscutter.data.custom.ScenePointEntry; +import emu.grasscutter.net.packet.Opcodes; +import emu.grasscutter.net.packet.PacketHandler; +import emu.grasscutter.net.packet.PacketOpcodes; +import emu.grasscutter.net.proto.PersonalSceneJumpReqOuterClass.PersonalSceneJumpReq; +import emu.grasscutter.server.game.GameSession; +import emu.grasscutter.server.packet.send.PacketPersonalSceneJumpRsp; +import emu.grasscutter.utils.Position; + + +@Opcodes(PacketOpcodes.PersonalSceneJumpReq) +public class HandlerPersonalSceneJumpReq extends PacketHandler { + + @Override + public void handle(GameSession session, byte[] header, byte[] payload) throws Exception { + PersonalSceneJumpReq req = PersonalSceneJumpReq.parseFrom(payload); + + // get the scene point + String code = session.getPlayer().getSceneId() + "_" + req.getPointId(); + ScenePointEntry scenePointEntry = GameData.getScenePointEntries().get(code); + + if (scenePointEntry != null) { + float x = scenePointEntry.getPointData().getTranPos().getX(); + float y = scenePointEntry.getPointData().getTranPos().getY(); + float z = scenePointEntry.getPointData().getTranPos().getZ(); + Position pos = new Position(x, y, z); + int sceneId = scenePointEntry.getPointData().getTranSceneId(); + + session.getPlayer().getWorld().transferPlayerToScene(session.getPlayer(), sceneId, pos); + session.send(new PacketPersonalSceneJumpRsp(sceneId, pos)); + } + + } + +} diff --git a/src/main/java/emu/grasscutter/server/packet/send/PacketPersonalSceneJumpRsp.java b/src/main/java/emu/grasscutter/server/packet/send/PacketPersonalSceneJumpRsp.java new file mode 100644 index 000000000..59065b5f8 --- /dev/null +++ b/src/main/java/emu/grasscutter/server/packet/send/PacketPersonalSceneJumpRsp.java @@ -0,0 +1,20 @@ +package emu.grasscutter.server.packet.send; + +import emu.grasscutter.net.packet.BasePacket; +import emu.grasscutter.net.packet.PacketOpcodes; +import emu.grasscutter.net.proto.PersonalSceneJumpRspOuterClass.PersonalSceneJumpRsp; +import emu.grasscutter.utils.Position; + +public class PacketPersonalSceneJumpRsp extends BasePacket { + + public PacketPersonalSceneJumpRsp(int sceneId, Position pos) { + super(PacketOpcodes.PersonalSceneJumpRsp); + + PersonalSceneJumpRsp proto = PersonalSceneJumpRsp.newBuilder() + .setDestSceneId(sceneId) + .setDestPos(pos.toProto()) + .build(); + + this.setData(proto); + } +} From 128f76700296228a80cd10c2e7ed10880fa5fd0b Mon Sep 17 00:00:00 2001 From: Scirese <62688390+Scirese@users.noreply.github.com> Date: Thu, 5 May 2022 21:53:38 +0800 Subject: [PATCH 06/11] Update CNLanguage to match with the latest EN version --- .../emu/grasscutter/languages/CNLanguage.java | 40 ++++++++++--------- 1 file changed, 22 insertions(+), 18 deletions(-) diff --git a/src/main/java/emu/grasscutter/languages/CNLanguage.java b/src/main/java/emu/grasscutter/languages/CNLanguage.java index 48123c778..ead3b4147 100644 --- a/src/main/java/emu/grasscutter/languages/CNLanguage.java +++ b/src/main/java/emu/grasscutter/languages/CNLanguage.java @@ -45,16 +45,25 @@ public final class CNLanguage { public String Invalid_playerId = "无效的玩家ID."; public String Player_not_found = "未找到此玩家."; public String Player_is_offline = "此玩家已离线."; + public String Invalid_amount = "无效的数量."; + public String Invalid_arguments = "无效的命令参数."; + public String Invalid_artifact_id = "无效的圣遗物ID."; + public String Invalid_avatar_id = "无效的角色ID."; + public String Invalid_avatar_level = "无效的角色等级."; + public String Invalid_entity_id = "无效的物品ID."; public String Invalid_item_id = "无效的物品ID."; - public String Invalid_item_or_player_id = "无效的玩家或物品ID."; + public String Invalid_item_level = "无效的物品等级."; + public String Invalid_item_refinement = "无效的精炼等级."; + public String Invalid_UID = "无效的UID."; public String Enabled = "启用"; public String Disabled = "禁用"; public String No_command_found = "未找到命令."; public String Help = "帮助"; public String Player_not_found_or_offline = "此玩家不存在或已离线."; - public String Invalid_arguments = "无效的参数."; public String Success = "成功"; - public String Invalid_entity_id = "无效的实体ID."; + public String Target_cleared = "已清除选择目标"; + public String Target_set = "接下来的命令将默认以 @{uid} 为目标。输入命令时不必继续携带UID参数。"; + public String Target_needed = "此命令需要指定一个目标用户. 输入命令时携带 <@UID> 参数或使用 /target @UID 来指定一个默认目标用户."; // Help public String Help_usage = " 用法: "; @@ -63,7 +72,6 @@ public final class CNLanguage { // Account public String Modify_user_account = "修改用户帐户"; - public String Invalid_UID = "无效的UID."; public String Account_exists = "账户已存在."; public String Account_create_UID = "UID为 {uid} 的账户已创建."; public String Account_delete = "已删除账户."; @@ -80,7 +88,7 @@ public final class CNLanguage { public String Change_screen = "切换到场景 "; public String Change_screen_not_exist = "此场景不存在。"; - // Clear + // Cleart_or_playerId public String Clear_weapons = "已清除 {name} 的武器."; public String Clear_artifacts = "已清除 {name} 的圣遗物 ."; public String Clear_materials = "已清除 {name} 的材料."; @@ -90,8 +98,9 @@ public final class CNLanguage { public String Clear_everything = "已清除 {name} 的所有物品."; // Coop - public String Coop_usage = "用法: coop <玩家ID> <房主的玩家ID>"; - + public String Coop_usage = "用法: coop <房主的UID>"; + public String Coop_success = "已将{target}拉进{host}的世界."; + // Drop public String Drop_usage = "用法: drop <物品ID|物品名> [数量]"; public String Drop_dropped_of = "已在地上丢弃 {amount} 个 {item}."; @@ -103,22 +112,17 @@ public final class CNLanguage { public String EnterDungeon_you_in_that_dungeon = "你已经在此副本中了。"; // GiveAll - public String GiveAll_usage = "用法: giveall [玩家] [数量]"; + public String GiveAll_usage = "用法: giveall [数量]"; public String GiveAll_item = "正在给予所有物品..."; public String GiveAll_done = "完成。"; - public String GiveAll_invalid_amount_or_playerId = "无效的数量或玩家ID"; // GiveArtifact public String GiveArtifact_usage = "用法: giveart|gart [玩家] <圣遗物Id> <主词条Id> [<副词条Id>[,<被强化次数>]]... [等级]"; - public String GiveArtifact_invalid_artifact_id = "无效的圣遗物Id."; public String GiveArtifact_given = "已将 {itemId} 给予 {target}."; // GiveChar public String GiveChar_usage = "用法: givechar <p玩家> <角色Id|角色名> [等级]"; public String GiveChar_given = "将等级为 {level} 的 {avatarId} 给予 {target}."; - public String GiveChar_invalid_avatar_id = "无效的角色ID"; - public String GiveChar_invalid_avatar_level = "无效的角色等级."; - public String GiveChar_invalid_avatar_or_player_id = "无效的角色ID或玩家ID."; // Give public String Give_usage = "用法: give [玩家名] <物品ID|物品名> [数量] [等级] "; @@ -129,7 +133,8 @@ public final class CNLanguage { public String Give_given_level = "已将 {amount} 个等级为 {lvl} 的 {item} 给与 {target}."; // GodMode - public String Godmode_status = "设置 {name} 的无敌模式为 {status} "; + public String Godmode_usage = "用法: godmode [on|off|toggle]"; + public String Godmode_status = "设置 {name} 的无敌模式为: {status} "; // Heal public String Heal_message = "所有角色已被治疗。"; @@ -151,7 +156,7 @@ public final class CNLanguage { public String List_message = "现有 {size} 名玩家在线:"; // Permission - public String Permission_usage = "用法: permission <add|remove> <用户名> <权限名>"; + public String Permission_usage = "用法: permission <add|remove> <权限名>"; public String Permission_add = "权限已添加。"; public String Permission_have_permission = "此玩家已拥有此权限!"; public String Permission_remove = "权限已移除。"; @@ -263,6 +268,7 @@ public final class CNLanguage { public String Talent_set_q = "设置元素爆发(q技能)等级为 {level}."; public String Talent_invalid_skill_id = "无效的技能ID。"; public String Talent_set_this = "技能等级已设为 {level}."; + public String Talent_set_id = "将技能 {id} 的等级设为 {level}."; public String Talent_invalid_talent_level = "无效的技能等级。"; public String Talent_normal_attack_id = "普通攻击技能ID {id}."; public String Talent_e_skill_id = "元素战技(e技能)ID {id}."; @@ -272,9 +278,7 @@ public final class CNLanguage { public String TeleportAll_message = "此命令仅在多人游戏下可用。"; // Teleport - public String Teleport_usage_server = "用法: /tp @<玩家ID> <x> <y> <z> [场景ID]"; - public String Teleport_usage = "用法: /tp @<玩家ID,不指定则为你自己> <x> <y> <z> [场景ID]"; - public String Teleport_specify_player_id = "你必须指定一个玩家。"; + public String Teleport_usage_server = "用法: /tp <x> <y> <z> [场景ID]"; public String Teleport_invalid_position = "无效的位置。"; public String Teleport_message = "已将 {name} 传送到场景 {id} ,坐标 {x},{y},{z}"; From 224a60de1be99feecbf5308967f5477e5af4e9c6 Mon Sep 17 00:00:00 2001 From: Ljzd-PRO <63289359+Ljzd-PRO@users.noreply.github.com> Date: Fri, 6 May 2022 04:32:09 +0800 Subject: [PATCH 07/11] Change the usage of command `permission` in README.md (#557) * Change the command `permission` usage * Change the command `permission` usage --- README.md | 2 +- README_zh-CN.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 8119b3f30..bbef2f834 100644 --- a/README.md +++ b/README.md @@ -125,7 +125,7 @@ There is a dummy user named "Server" in every player's friends list that you can | kick | kick \<player> | server.kick | Both side | Kicks the specified player from the server. (WIP) | k | | killall | killall [playerUid] [sceneId] | server.killall | Both side | Kills all entities in the current scene or specified scene of the corresponding player. | | | list | list | | Both side | Lists online players. | | -| permission | permission <add\|remove> \<username> \<permission> | * | Both side | Grants or removes a permission for a user. | | +| permission | permission <add\|remove> \<UID> \<permission> | * | Both side | Grants or removes a permission for a user. | | | position | position | | Client only | Sends your current coordinates. | pos | | reload | reload | server.reload | Both side | Reloads the server config | | | resetconst | resetconst [all] | player.resetconstellation | Client only | Resets the constellation level on your currently selected character, will need to relog after using the command to see any changes. | resetconstellation | diff --git a/README_zh-CN.md b/README_zh-CN.md index 4b4d57131..66878b4f4 100644 --- a/README_zh-CN.md +++ b/README_zh-CN.md @@ -126,7 +126,7 @@ chmod +x gradlew | kick | kick \<uid> | server.kick | 均可使用 | 从服务器中踢出指定玩家 (WIP) | k | | killall | killall [uid] [场景ID] | server.killall | 均可使用 | 杀死指定玩家世界中所在或指定场景的全部生物 | | | list | list | | 均可使用 | 列出在线玩家 | | -| permission | permission <add\|remove> <用户名> <权限节点> | * | 均可使用 | 添加或移除玩家的权限 | | +| permission | permission <add\|remove> <UID> <权限节点> | * | 均可使用 | 添加或移除玩家的权限 | | | position | position | | 仅客户端 | 获取当前坐标 | pos | | reload | reload | server.reload | 均可使用 | 重载服务器配置 | | | resetconst | resetconst [all] | player.resetconstellation | 仅客户端 | 重置当前角色的命座,重新登录即可生效 | resetconstellation | From bafde8693d0660dc9939f6bcfd9ef2367facd65e Mon Sep 17 00:00:00 2001 From: gentlespoon <github@gentlespoon.com> Date: Thu, 5 May 2022 09:27:42 -0700 Subject: [PATCH 08/11] Fixes #529: fixed stamina abnormal. added fall to death. Stamina is still WIP. - Currently stamina consumption is not affected by the use of foods, talents, or the environment. - Charged attacks do no require stamina yet. - Will be fixed tomorrow. --- .../managers/MotionManager/MotionManager.java | 227 ++++++++++++++++++ .../emu/grasscutter/game/player/Player.java | 34 +++ .../recv/HandlerCombatInvocationsNotify.java | 73 +----- .../recv/HandlerEvtDoSkillSuccNotify.java | 26 ++ 4 files changed, 291 insertions(+), 69 deletions(-) create mode 100644 src/main/java/emu/grasscutter/game/managers/MotionManager/MotionManager.java create mode 100644 src/main/java/emu/grasscutter/server/packet/recv/HandlerEvtDoSkillSuccNotify.java diff --git a/src/main/java/emu/grasscutter/game/managers/MotionManager/MotionManager.java b/src/main/java/emu/grasscutter/game/managers/MotionManager/MotionManager.java new file mode 100644 index 000000000..d8d6f25b0 --- /dev/null +++ b/src/main/java/emu/grasscutter/game/managers/MotionManager/MotionManager.java @@ -0,0 +1,227 @@ +package emu.grasscutter.game.managers.MotionManager; + +import emu.grasscutter.Grasscutter; +import emu.grasscutter.game.entity.GameEntity; +import emu.grasscutter.game.player.Player; +import emu.grasscutter.game.props.FightProperty; +import emu.grasscutter.game.props.LifeState; +import emu.grasscutter.game.props.PlayerProperty; +import emu.grasscutter.net.proto.EntityMoveInfoOuterClass; +import emu.grasscutter.net.proto.MotionStateOuterClass.MotionState; +import emu.grasscutter.net.proto.VectorOuterClass; +import emu.grasscutter.server.game.GameSession; +import emu.grasscutter.server.packet.send.PacketEntityFightPropUpdateNotify; +import emu.grasscutter.server.packet.send.PacketLifeStateChangeNotify; +import emu.grasscutter.server.packet.send.PacketPlayerPropNotify; +import emu.grasscutter.utils.Position; + +import java.util.ArrayList; +import java.lang.Math; + +public class MotionManager { + + private enum Consumption { + None(0), + + // consumers + CLIMB_START(-500), + CLIMBING(-150), + CLIMB_JUMP(-2500), + DASH(-1800), + SPRINT(-360), + FLY(-60), + SWIM_DASH_START(-200), + SWIM_DASH(-200), + SWIMMING(-80), + + // restorers + STANDBY(500), + RUN(500), + WALK(500), + STANDBY_MOVE(500); + + public final int amount; + Consumption(int amount) { + this.amount = amount; + } + } + + private EntityMoveInfoOuterClass.EntityMoveInfo moveInfo; + + private MotionState previousState = MotionState.MOTION_STANDBY; + private ArrayList<Position> previousCoordinates = new ArrayList<>(); + private final Player player; + + private float landSpeed = 0; + + public MotionManager(Player player) { + previousCoordinates.add(new Position(0,0,0)); + this.player = player; + } + + public void handle(GameSession session, GameEntity entity, EntityMoveInfoOuterClass.EntityMoveInfo moveInfo) { + MotionState state = moveInfo.getMotionInfo().getState(); + setMoveInfo(moveInfo); + if (state == MotionState.MOTION_LAND_SPEED) { + setLandSpeed(moveInfo.getMotionInfo().getSpeed().getY()); + } + if (state == MotionState.MOTION_FALL_ON_GROUND) { + handleFallOnGround(session, entity); + } + } + + public void tick() { + if(Grasscutter.getConfig().OpenStamina){ + EntityMoveInfoOuterClass.EntityMoveInfo mInfo = moveInfo; + if (mInfo == null) { + return; + } + + MotionState state = moveInfo.getMotionInfo().getState(); + Consumption consumption = Consumption.None; + + boolean isMoving = false; + VectorOuterClass.Vector posVector = moveInfo.getMotionInfo().getPos(); + Position currentCoordinates = new Position(posVector.getX(), posVector.getY(), posVector.getZ()); + + float diffX = currentCoordinates.getX() - previousCoordinates.get(0).getX(); + float diffY = currentCoordinates.getY() - previousCoordinates.get(0).getY(); + float diffZ = currentCoordinates.getZ() - previousCoordinates.get(0).getZ(); + + if (Math.abs(diffX) > 0.3 || Math.abs(diffY) > 0.3 || Math.abs(diffZ) > 0.3) { + isMoving = true; + } + + if (isMoving) { + // TODO: refactor these conditions. + // CLIMB + if (state == MotionState.MOTION_CLIMB) { + if (previousState != MotionState.MOTION_CLIMB && previousState != MotionState.MOTION_CLIMB_JUMP) { + consumption = Consumption.CLIMB_START; + } else { + consumption = Consumption.CLIMBING; + } + } + // JUMP + if (state == MotionState.MOTION_CLIMB_JUMP) { + if (previousState != MotionState.MOTION_CLIMB_JUMP) { + consumption = Consumption.CLIMB_JUMP; + } + } + if (state == MotionState.MOTION_JUMP) { + if (previousState == MotionState.MOTION_CLIMB) { + consumption = Consumption.CLIMB_JUMP; + } + } + // SWIM + if (state == MotionState.MOTION_SWIM_MOVE) { + consumption = Consumption.SWIMMING; + } + if (state == MotionState.MOTION_SWIM_DASH) { + if (previousState != MotionState.MOTION_SWIM_DASH) { + consumption = Consumption.SWIM_DASH_START; + } else { + consumption = Consumption.SWIM_DASH; + } + } + // DASH + if (state == MotionState.MOTION_DASH) { + if (previousState == MotionState.MOTION_DASH) { + consumption = Consumption.SPRINT; + } else { + consumption = Consumption.DASH; + } + } + // RUN and WALK + if (state == MotionState.MOTION_RUN) { + consumption = Consumption.RUN; + } + if (state == MotionState.MOTION_WALK) { + consumption = Consumption.WALK; + } + // FLY + if (state == MotionState.MOTION_FLY) { + consumption = Consumption.FLY; + } + } + // STAND + if (state == MotionState.MOTION_STANDBY) { + consumption = Consumption.STANDBY; + } + if (state == MotionState.MOTION_STANDBY_MOVE) { + consumption = Consumption.STANDBY_MOVE; + } + + GameSession session = player.getSession(); + updateStamina(session, consumption.amount); + session.send(new PacketPlayerPropNotify(session.getPlayer(), PlayerProperty.PROP_CUR_PERSIST_STAMINA)); + + Grasscutter.getLogger().debug(session.getPlayer().getProperty(PlayerProperty.PROP_CUR_PERSIST_STAMINA) + " " + state + " " + isMoving + " " + consumption + " " + consumption.amount); + + previousState = state; + previousCoordinates.add(currentCoordinates); + if (previousCoordinates.size() > 3) { + previousCoordinates.remove(0); + } + } + } + + public void updateStamina(GameSession session, int amount) { + if (amount == 0) { + return; + } + int currentStamina = session.getPlayer().getProperty(PlayerProperty.PROP_CUR_PERSIST_STAMINA); + int playerMaxStamina = session.getPlayer().getProperty(PlayerProperty.PROP_MAX_STAMINA); + int newStamina = currentStamina + amount; + if (newStamina < 0) { + newStamina = 0; + } + if (newStamina > playerMaxStamina) { + newStamina = playerMaxStamina; + } + session.getPlayer().setProperty(PlayerProperty.PROP_CUR_PERSIST_STAMINA, newStamina); + } + + public void setMoveInfo(EntityMoveInfoOuterClass.EntityMoveInfo moveInfo) { + this.moveInfo = moveInfo; + } + + public EntityMoveInfoOuterClass.EntityMoveInfo getMoveInfo() { + return moveInfo; + } + + public void handleFallOnGround(GameSession session, GameEntity entity) { + float currentHP = entity.getFightProperty(FightProperty.FIGHT_PROP_CUR_HP); + float maxHP = entity.getFightProperty(FightProperty.FIGHT_PROP_MAX_HP); + float damage = 0; + Grasscutter.getLogger().debug("LandSpeed: " + landSpeed); + if (landSpeed < -23.5) { + damage = (float)(maxHP * 0.33); + } + if (landSpeed < -25) { + damage = (float)(maxHP * 0.5); + } + if (landSpeed < -26.5) { + damage = (float)(maxHP * 0.66); + } + if (landSpeed < -28) { + damage = (maxHP * 1); + } + float newHP = currentHP - damage; + if (newHP < 0) { + newHP = 0; + } + Grasscutter.getLogger().debug("Max: " + maxHP + "\tCurr: " + currentHP + "\tDamage: " + damage + "\tnewHP: " + newHP); + entity.setFightProperty(FightProperty.FIGHT_PROP_CUR_HP, newHP); + entity.getWorld().broadcastPacket(new PacketEntityFightPropUpdateNotify(entity, FightProperty.FIGHT_PROP_CUR_HP)); + if (newHP == 0) { + entity.getWorld().broadcastPacket(new PacketLifeStateChangeNotify(0, entity, LifeState.LIFE_DEAD)); + session.getPlayer().getScene().removeEntity(entity); + entity.onDeath(0); + } + } + + public void setLandSpeed(float landSpeed) { + this.landSpeed = landSpeed; + } +} diff --git a/src/main/java/emu/grasscutter/game/player/Player.java b/src/main/java/emu/grasscutter/game/player/Player.java index c76f46bf0..b1abda002 100644 --- a/src/main/java/emu/grasscutter/game/player/Player.java +++ b/src/main/java/emu/grasscutter/game/player/Player.java @@ -21,6 +21,7 @@ import emu.grasscutter.game.inventory.GameItem; import emu.grasscutter.game.inventory.Inventory; import emu.grasscutter.game.mail.Mail; import emu.grasscutter.game.mail.MailHandler; +import emu.grasscutter.game.managers.MotionManager.MotionManager; import emu.grasscutter.game.props.ActionReason; import emu.grasscutter.game.props.EntityType; import emu.grasscutter.game.props.PlayerProperty; @@ -121,6 +122,8 @@ public class Player { @Transient private final InvokeHandler<AbilityInvokeEntry> clientAbilityInitFinishHandler; private MapMarksManager mapMarksManager; + @Transient private MotionManager motionManager; + @Deprecated @SuppressWarnings({"rawtypes", "unchecked"}) // Morphia only! @@ -161,6 +164,7 @@ public class Player { this.shopLimit = new ArrayList<>(); this.messageHandler = null; this.mapMarksManager = new MapMarksManager(); + this.motionManager = new MotionManager(this); } // On player creation @@ -187,6 +191,7 @@ public class Player { this.getRotation().set(0, 307, 0); this.messageHandler = null; this.mapMarksManager = new MapMarksManager(); + this.motionManager = new MotionManager(this); } public int getUid() { @@ -969,6 +974,8 @@ public class Player { return mapMarksManager; } + public MotionManager getMotionManager() { return motionManager; } + public synchronized void onTick() { // Check ping if (this.getLastPingTime() > System.currentTimeMillis() + 60000) { @@ -997,8 +1004,35 @@ public class Player { this.resetSendPlayerLocTime(); } } + + scheduleStaminaNotify(); } + private void scheduleStaminaNotify() { + // stamina tick + EntityMoveInfoOuterClass.EntityMoveInfo moveInfo = getMotionManager().getMoveInfo(); + if (moveInfo == null) { + return; + } + + if (getMotionManager().getMoveInfo().getMotionInfo().getState() == MotionStateOuterClass.MotionState.MOTION_STANDBY) { + if (getProperty(PlayerProperty.PROP_CUR_PERSIST_STAMINA) == getProperty(PlayerProperty.PROP_MAX_STAMINA) ) { + return; + } + } + + for (int i = 0; i <= 1000; i+=200) { + Timer timer = new Timer(); + timer.schedule(new TimerTask() { + @Override + public void run() { + getMotionManager().tick(); + } + }, i); + } + } + + public void resetSendPlayerLocTime() { this.nextSendPlayerLocTime = System.currentTimeMillis() + 5000; } diff --git a/src/main/java/emu/grasscutter/server/packet/recv/HandlerCombatInvocationsNotify.java b/src/main/java/emu/grasscutter/server/packet/recv/HandlerCombatInvocationsNotify.java index 2d0ceac8b..878997e22 100644 --- a/src/main/java/emu/grasscutter/server/packet/recv/HandlerCombatInvocationsNotify.java +++ b/src/main/java/emu/grasscutter/server/packet/recv/HandlerCombatInvocationsNotify.java @@ -1,8 +1,9 @@ package emu.grasscutter.server.packet.recv; -import emu.grasscutter.Grasscutter; import emu.grasscutter.game.entity.GameEntity; -import emu.grasscutter.game.props.PlayerProperty; +import emu.grasscutter.game.managers.MotionManager.MotionManager; +import emu.grasscutter.game.props.FightProperty; +import emu.grasscutter.game.props.LifeState; import emu.grasscutter.net.packet.Opcodes; import emu.grasscutter.net.packet.PacketOpcodes; import emu.grasscutter.net.proto.CombatInvocationsNotifyOuterClass.CombatInvocationsNotify; @@ -11,13 +12,9 @@ import emu.grasscutter.net.proto.EntityMoveInfoOuterClass.EntityMoveInfo; import emu.grasscutter.net.proto.EvtBeingHitInfoOuterClass.EvtBeingHitInfo; import emu.grasscutter.net.packet.PacketHandler; import emu.grasscutter.net.proto.MotionStateOuterClass.MotionState; -import emu.grasscutter.net.proto.VectorOuterClass.Vector; import emu.grasscutter.server.game.GameSession; import emu.grasscutter.server.packet.send.*; -import java.util.Arrays; -import java.util.Collection; - @Opcodes(PacketOpcodes.CombatInvocationsNotify) public class HandlerCombatInvocationsNotify extends PacketHandler { @@ -35,7 +32,6 @@ public class HandlerCombatInvocationsNotify extends PacketHandler { // Handle movement EntityMoveInfo moveInfo = EntityMoveInfo.parseFrom(entry.getCombatData()); GameEntity entity = session.getPlayer().getScene().getEntityById(moveInfo.getEntityId()); - MotionState state = moveInfo.getMotionInfo().getState(); if (entity != null) { //move entity.getPosition().set(moveInfo.getMotionInfo().getPos()); @@ -43,56 +39,7 @@ public class HandlerCombatInvocationsNotify extends PacketHandler { entity.setLastMoveSceneTimeMs(moveInfo.getSceneTime()); entity.setLastMoveReliableSeq(moveInfo.getReliableSeq()); entity.setMotionState(moveInfo.getMotionInfo().getState()); - - if(Grasscutter.getConfig().OpenStamina){ - //consume stamina - int curStamina = session.getPlayer().getProperty(PlayerProperty.PROP_CUR_PERSIST_STAMINA); - int maxStamina = session.getPlayer().getProperty(PlayerProperty.PROP_MAX_STAMINA); - if (CONSUME_STAMINA_LIST.contains(state)) { - - //In the water exhausted stamina - - //Climbing the wall stays in place - - //Sprint in the water - if (state == MotionState.MOTION_SWIM_DASH) { - curStamina -= 700; - } - //wall jump - else if (state == MotionState.MOTION_CLIMB_JUMP) { - curStamina -= 2000; - } - //climb the wall slowly - else if (state == MotionState.MOTION_CLIMB) { - curStamina -= 800; - } - else if (state == MotionState.MOTION_DASH_BEFORE_SHAKE) { - curStamina -= 2500; - } - else { - curStamina -= 500; - } - - session.getPlayer().setProperty(PlayerProperty.PROP_CUR_PERSIST_STAMINA, curStamina); - session.send(new PacketPlayerPropNotify(session.getPlayer(), PlayerProperty.PROP_CUR_PERSIST_STAMINA)); - break; - } - //restore stamina - if (RESTORE_STAMINA_LIST.contains(state)) { - if(state == MotionState.MOTION_STANDBY) { - Vector speed = moveInfo.getMotionInfo().getSpeed(); - if(speed.getX() != 0 && speed.getZ() != 0 && speed.getY() != 0) { - break; - } - } - curStamina += 1000; - if (curStamina >= maxStamina) { - curStamina = maxStamina; - } - session.getPlayer().setProperty(PlayerProperty.PROP_CUR_PERSIST_STAMINA, curStamina); - session.send(new PacketPlayerPropNotify(session.getPlayer(), PlayerProperty.PROP_CUR_PERSIST_STAMINA)); - } - } + session.getPlayer().getMotionManager().handle(session, entity, moveInfo); } break; default: @@ -111,17 +58,5 @@ public class HandlerCombatInvocationsNotify extends PacketHandler { } } - private static MotionState[] consumeStaminaTypes = new MotionState[]{ - MotionState.MOTION_CLIMB, MotionState.MOTION_CLIMB_JUMP, MotionState.MOTION_SWIM_DASH, - MotionState.MOTION_SWIM_MOVE, MotionState.MOTION_FLY, MotionState.MOTION_DASH, - MotionState.MOTION_DASH_BEFORE_SHAKE, MotionState.MOTION_FIGHT, MotionState.MOTION_JUMP_UP_WALL_FOR_STANDBY, - MotionState.MOTION_FLY_SLOW - }; - private static MotionState[] restoreStaminaTypes = new MotionState[]{ - MotionState.MOTION_STANDBY, MotionState.MOTION_RUN, MotionState.MOTION_WALK, - MotionState.MOTION_STANDBY_MOVE - }; - private static final Collection<MotionState> CONSUME_STAMINA_LIST = Arrays.asList(consumeStaminaTypes); - private static final Collection<MotionState> RESTORE_STAMINA_LIST = Arrays.asList(restoreStaminaTypes); } diff --git a/src/main/java/emu/grasscutter/server/packet/recv/HandlerEvtDoSkillSuccNotify.java b/src/main/java/emu/grasscutter/server/packet/recv/HandlerEvtDoSkillSuccNotify.java new file mode 100644 index 000000000..d1db944d2 --- /dev/null +++ b/src/main/java/emu/grasscutter/server/packet/recv/HandlerEvtDoSkillSuccNotify.java @@ -0,0 +1,26 @@ +package emu.grasscutter.server.packet.recv; + +import emu.grasscutter.Grasscutter; +import emu.grasscutter.net.packet.Opcodes; +import emu.grasscutter.net.packet.PacketHandler; +import emu.grasscutter.net.packet.PacketOpcodes; +import emu.grasscutter.net.proto.EvtDoSkillSuccNotifyOuterClass.EvtDoSkillSuccNotify; +import emu.grasscutter.server.game.GameSession; + +@Opcodes(PacketOpcodes.EvtDoSkillSuccNotify) +public class HandlerEvtDoSkillSuccNotify extends PacketHandler { + + @Override + public void handle(GameSession session, byte[] header, byte[] payload) throws Exception { + EvtDoSkillSuccNotify notify = EvtDoSkillSuccNotify.parseFrom(payload); + // TODO: Will be used for deducting stamina for charged skills. + + int caster = notify.getCasterId(); + int skill = notify.getSkillId(); + + // Grasscutter.getLogger().warn(caster + "\t" + skill); + +// session.getPlayer().getScene().broadcastPacket(new PacketEvtAvatarStandUpNotify(notify)); + } + +} From b2955274ab0e662b3ebc5ab0dcb7bf3162acf033 Mon Sep 17 00:00:00 2001 From: ShiroSaki <62388797+ShigemoriHakura@users.noreply.github.com> Date: Fri, 6 May 2022 07:43:45 +0800 Subject: [PATCH 09/11] Add all AvatarExpedition protos Expedition system has almost done but still has some bug so it will be uploaded later From a045142a414c2d131a380f78968a39d574e35db4 Mon Sep 17 00:00:00 2001 From: Melledy <52122272+Melledy@users.noreply.github.com> Date: Thu, 5 May 2022 17:17:27 -0700 Subject: [PATCH 10/11] Kick player if they use an invalid resources folder --- .../server/packet/recv/HandlerSetPlayerBornDataReq.java | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/main/java/emu/grasscutter/server/packet/recv/HandlerSetPlayerBornDataReq.java b/src/main/java/emu/grasscutter/server/packet/recv/HandlerSetPlayerBornDataReq.java index cae0cce65..02cdb1b8a 100644 --- a/src/main/java/emu/grasscutter/server/packet/recv/HandlerSetPlayerBornDataReq.java +++ b/src/main/java/emu/grasscutter/server/packet/recv/HandlerSetPlayerBornDataReq.java @@ -37,6 +37,13 @@ public class HandlerSetPlayerBornDataReq extends PacketHandler { return; } + // Make sure resources folder is set + if (!GameData.getAvatarDataMap().containsKey(avatarId)) { + Grasscutter.getLogger().error("No avatar data found! Please check your ExcelBinOutput folder."); + session.close(); + return; + } + String nickname = req.getNickName(); if (nickname == null) { nickname = "Traveler"; From 81998b9cf9a56cbbcb395126ad077fb61cd777fd Mon Sep 17 00:00:00 2001 From: memetrollsXD <paris@memetrolls.net> Date: Fri, 6 May 2022 04:11:08 +0200 Subject: [PATCH 11/11] Customise sender and title too. Add statement of use --- src/main/java/emu/grasscutter/Config.java | 4 +++- src/main/java/emu/grasscutter/data/GameData.java | 2 -- .../emu/grasscutter/database/DatabaseHelper.java | 2 -- .../emu/grasscutter/net/packet/PacketOpcodes.java | 1 - .../packet/recv/HandlerSetPlayerBornDataReq.java | 12 ++++-------- 5 files changed, 7 insertions(+), 14 deletions(-) diff --git a/src/main/java/emu/grasscutter/Config.java b/src/main/java/emu/grasscutter/Config.java index dd24ac8a0..e7536b588 100644 --- a/src/main/java/emu/grasscutter/Config.java +++ b/src/main/java/emu/grasscutter/Config.java @@ -82,7 +82,9 @@ public final class Config { public int ServerAvatarId = 10000007; public int[] WelcomeEmotes = {2007, 1002, 4010}; public String WelcomeMotd = "Welcome to Grasscutter emu"; - public String WelcomeMailContent = "Hi there!\r\nFirst of all, welcome to Grasscutter. If you have any issues, please let us know so that Lawnmower can help you! \r\n\r\nCheck out our:\r\n<type=\"browser\" text=\"Discord\" href=\"https://discord.gg/T5vZU6UyeG\"/> <type=\"browser\" text=\"GitHub\" href=\"https://github.com/Melledy/Grasscutter\"/>"; + public String WelcomeMailTitle = "Welcome to Grasscutter!"; + public String WelcomeMailSender = "Lawnmower"; + public String WelcomeMailContent = "Hi there!\r\nFirst of all, welcome to Grasscutter. If you have any issues, please let us know so that Lawnmower can help you! \r\n\r\nCheck out our:\r\n<type=\"browser\" text=\"Discord\" href=\"https://discord.gg/T5vZU6UyeG\"/>"; public Mail.MailItem[] WelcomeMailItems = { new Mail.MailItem(13509, 1, 1), new Mail.MailItem(201, 10000, 1), diff --git a/src/main/java/emu/grasscutter/data/GameData.java b/src/main/java/emu/grasscutter/data/GameData.java index e97e1e7de..692427496 100644 --- a/src/main/java/emu/grasscutter/data/GameData.java +++ b/src/main/java/emu/grasscutter/data/GameData.java @@ -74,8 +74,6 @@ public class GameData { private static Map<Integer, List<ShopGoodsData>> shopGoods = new HashMap<>(); private static final IntList scenePointIdList = new IntArrayList(); - public static char EJWOA = 's'; - public static Int2ObjectMap<?> getMapByResourceDef(Class<?> resourceDefinition) { Int2ObjectMap<?> map = null; diff --git a/src/main/java/emu/grasscutter/database/DatabaseHelper.java b/src/main/java/emu/grasscutter/database/DatabaseHelper.java index 97bd6d739..f63798988 100644 --- a/src/main/java/emu/grasscutter/database/DatabaseHelper.java +++ b/src/main/java/emu/grasscutter/database/DatabaseHelper.java @@ -234,6 +234,4 @@ public final class DatabaseHelper { DeleteResult result = DatabaseManager.getDatastore().delete(mail); return result.wasAcknowledged(); } - - public static char AWJVN = 'e'; } diff --git a/src/main/java/emu/grasscutter/net/packet/PacketOpcodes.java b/src/main/java/emu/grasscutter/net/packet/PacketOpcodes.java index 0a0c577d0..4d9eb57e8 100644 --- a/src/main/java/emu/grasscutter/net/packet/PacketOpcodes.java +++ b/src/main/java/emu/grasscutter/net/packet/PacketOpcodes.java @@ -3,7 +3,6 @@ package emu.grasscutter.net.packet; public class PacketOpcodes { // Empty public static final int NONE = 0; - public static final char ONLWE = 'u'; // Opcodes public static final int AbilityChangeNotify = 1179; diff --git a/src/main/java/emu/grasscutter/server/packet/recv/HandlerSetPlayerBornDataReq.java b/src/main/java/emu/grasscutter/server/packet/recv/HandlerSetPlayerBornDataReq.java index 02cdb1b8a..2487df063 100644 --- a/src/main/java/emu/grasscutter/server/packet/recv/HandlerSetPlayerBornDataReq.java +++ b/src/main/java/emu/grasscutter/server/packet/recv/HandlerSetPlayerBornDataReq.java @@ -85,15 +85,11 @@ public class HandlerSetPlayerBornDataReq extends PacketHandler { session.send(new BasePacket(PacketOpcodes.SetPlayerBornDataRsp)); // Default mail - char d = 'G'; - char e = 'r'; - char z = 'a'; - char u = 'c'; - char s = 't'; MailBuilder mailBuilder = new MailBuilder(player.getUid(), new Mail()); - mailBuilder.mail.mailContent.title = String.format("W%sl%som%s to %s%s%s%s%s%s%s%s%s%s%s!", DatabaseHelper.AWJVN, u, DatabaseHelper.AWJVN, d, e, z, GameData.EJWOA, GameData.EJWOA, u, PacketOpcodes.ONLWE, s, s, DatabaseHelper.AWJVN, e); - mailBuilder.mail.mailContent.sender = String.format("L%swnmow%s%s @ Gi%sH%sb", z, DatabaseHelper.AWJVN, e, s, PacketOpcodes.ONLWE); - mailBuilder.mail.mailContent.content = Grasscutter.getConfig().GameServer.WelcomeMailContent; + mailBuilder.mail.mailContent.title = Grasscutter.getConfig().GameServer.WelcomeMailTitle; + mailBuilder.mail.mailContent.sender = Grasscutter.getConfig().GameServer.WelcomeMailSender; + // Please credit Grasscutter if changing something here. We don't condone commercial use of the project. + mailBuilder.mail.mailContent.content = Grasscutter.getConfig().GameServer.WelcomeMailContent + "\n<type=\"browser\" text=\"GitHub\" href=\"https://github.com/Melledy/Grasscutter\"/>"; mailBuilder.mail.itemList.addAll(Arrays.asList(Grasscutter.getConfig().GameServer.WelcomeMailItems)); mailBuilder.mail.importance = 1; player.sendMail(mailBuilder.mail);