+1
-2
@@ -1,4 +1,3 @@
|
|||||||
# Generated from CLion Inspection settings
|
|
||||||
---
|
---
|
||||||
Checks: '-*,
|
Checks: '-*,
|
||||||
bugprone-argument-comment,
|
bugprone-argument-comment,
|
||||||
@@ -123,7 +122,6 @@ portability-simd-intrinsics,
|
|||||||
readability-avoid-const-params-in-decls,
|
readability-avoid-const-params-in-decls,
|
||||||
readability-const-return-type,
|
readability-const-return-type,
|
||||||
readability-container-size-empty,
|
readability-container-size-empty,
|
||||||
readability-convert-member-functions-to-static,
|
|
||||||
readability-delete-null-pointer,
|
readability-delete-null-pointer,
|
||||||
readability-deleted-default,
|
readability-deleted-default,
|
||||||
readability-inconsistent-declaration-parameter-name,
|
readability-inconsistent-declaration-parameter-name,
|
||||||
@@ -143,3 +141,4 @@ readability-static-definition-in-anonymous-namespace,
|
|||||||
readability-string-compare,
|
readability-string-compare,
|
||||||
readability-uniqueptr-delete-release,
|
readability-uniqueptr-delete-release,
|
||||||
readability-use-anyofallof'
|
readability-use-anyofallof'
|
||||||
|
...
|
||||||
@@ -7,9 +7,7 @@ Diagnostics:
|
|||||||
CompileFlags:
|
CompileFlags:
|
||||||
Add:
|
Add:
|
||||||
- "-ferror-limit=0"
|
- "-ferror-limit=0"
|
||||||
- "-D__FUNCTION__=\"dummy\""
|
- '-D__FUNCTION__="dummy"'
|
||||||
- "-Yumc/_HeaderOutputPredefine.h"
|
- "-Dnsel_CONFIG_SELECT_EXPECTED=nsel_EXPECTED_NONSTD"
|
||||||
- "-FImc/_HeaderOutputPredefine.h" # clangd bug can't find pch file
|
- "/std:c++20"
|
||||||
Remove:
|
- "-D_HAS_CXX23=1"
|
||||||
- "/Yu_HeaderOutputPredefine.h"
|
|
||||||
- "/FI_HeaderOutputPredefine.h"
|
|
||||||
+21
-15
@@ -7,26 +7,32 @@ jobs:
|
|||||||
build:
|
build:
|
||||||
runs-on: windows-latest
|
runs-on: windows-latest
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout repository
|
- name: Checkout
|
||||||
uses: actions/checkout@v2
|
uses: actions/checkout@v4
|
||||||
|
|
||||||
|
- name: Setup XMake
|
||||||
|
uses: xmake-io/github-action-setup-xmake@v1
|
||||||
|
|
||||||
|
- name: Cache
|
||||||
|
uses: actions/cache@v4
|
||||||
with:
|
with:
|
||||||
submodules: recursive
|
path: |
|
||||||
|
~/AppData/Local/.xmake
|
||||||
|
key: xmake-${{ hashFiles('xmake.lua') }}
|
||||||
|
restore-keys: |
|
||||||
|
xmake-
|
||||||
|
|
||||||
- uses: actions/checkout@v4
|
- name: Update Repo
|
||||||
|
run: xmake repo -u
|
||||||
|
|
||||||
- uses: xmake-io/github-action-setup-xmake@v1
|
- name: Update Project
|
||||||
with:
|
run: xmake f -a x64 -m release -p windows -v -y
|
||||||
xmake-version: branch@master
|
|
||||||
- run: |
|
|
||||||
xmake repo -u
|
|
||||||
|
|
||||||
- run: |
|
- name: Build Project
|
||||||
xmake f -a x64 -m release -p windows -v -y
|
run: xmake -v -y
|
||||||
|
|
||||||
- run: |
|
- name: Upload Artifact
|
||||||
xmake -w -y
|
uses: actions/upload-artifact@v4
|
||||||
|
|
||||||
- uses: actions/upload-artifact@v4
|
|
||||||
with:
|
with:
|
||||||
name: ${{ github.event.repository.name }}-windows-x64-${{ github.sha }}
|
name: ${{ github.event.repository.name }}-windows-x64-${{ github.sha }}
|
||||||
path: |
|
path: |
|
||||||
|
|||||||
@@ -7,26 +7,32 @@ jobs:
|
|||||||
build:
|
build:
|
||||||
runs-on: windows-latest
|
runs-on: windows-latest
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout repository
|
- name: Checkout
|
||||||
uses: actions/checkout@v2
|
uses: actions/checkout@v4
|
||||||
|
|
||||||
|
- name: Setup XMake
|
||||||
|
uses: xmake-io/github-action-setup-xmake@v1
|
||||||
|
|
||||||
|
- name: Cache
|
||||||
|
uses: actions/cache@v4
|
||||||
with:
|
with:
|
||||||
submodules: recursive
|
path: |
|
||||||
|
~/AppData/Local/.xmake
|
||||||
|
key: xmake-${{ hashFiles('xmake.lua') }}
|
||||||
|
restore-keys: |
|
||||||
|
xmake-
|
||||||
|
|
||||||
- uses: actions/checkout@v4
|
- name: Update Repo
|
||||||
|
run: xmake repo -u
|
||||||
|
|
||||||
- uses: xmake-io/github-action-setup-xmake@v1
|
- name: Update Project
|
||||||
with:
|
run: xmake f -a x64 -m release -p windows -v -y
|
||||||
xmake-version: branch@master
|
|
||||||
- run: |
|
|
||||||
xmake repo -u
|
|
||||||
|
|
||||||
- run: |
|
- name: Build Project
|
||||||
xmake f -a x64 -m release -p windows -v -y
|
run: xmake -v -y
|
||||||
|
|
||||||
- run: |
|
- name: Upload Artifact
|
||||||
xmake -w -y
|
uses: actions/upload-artifact@v4
|
||||||
|
|
||||||
- uses: actions/upload-artifact@v4
|
|
||||||
with:
|
with:
|
||||||
name: ${{ github.event.repository.name }}-windows-x64-${{ github.sha }}
|
name: ${{ github.event.repository.name }}-windows-x64-${{ github.sha }}
|
||||||
path: |
|
path: |
|
||||||
@@ -39,24 +45,26 @@ jobs:
|
|||||||
contents: write
|
contents: write
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4
|
- name: Checkout
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
|
||||||
- uses: actions/download-artifact@v4
|
- name: Download Artifact
|
||||||
|
uses: actions/download-artifact@v4
|
||||||
with:
|
with:
|
||||||
name: ${{ github.event.repository.name }}-windows-x64-${{ github.sha }}
|
name: ${{ github.event.repository.name }}-windows-x64-${{ github.sha }}
|
||||||
path: release/
|
path: artifact
|
||||||
|
|
||||||
- run: |
|
- name: Copy Files
|
||||||
cp LICENSE README.md release/
|
|
||||||
|
|
||||||
- name: Archive release
|
|
||||||
run: |
|
run: |
|
||||||
cd release
|
cp LICENSE README.md artifact/
|
||||||
zip -r ../${{ github.event.repository.name }}-windows-x64.zip *
|
|
||||||
cd ..
|
|
||||||
|
|
||||||
- uses: softprops/action-gh-release@v1
|
- name: Compress Artifact
|
||||||
|
run: |
|
||||||
|
zip -r ../${{ github.event.repository.name }}-windows-x64.zip *
|
||||||
|
working-directory: artifact
|
||||||
|
|
||||||
|
- name: Create Release
|
||||||
|
uses: softprops/action-gh-release@v1
|
||||||
with:
|
with:
|
||||||
append_body: true
|
|
||||||
files: |
|
files: |
|
||||||
${{ github.event.repository.name }}-windows-x64.zip
|
${{ github.event.repository.name }}-windows-x64.zip
|
||||||
@@ -16,3 +16,4 @@ build/
|
|||||||
/CMakeLists.txt
|
/CMakeLists.txt
|
||||||
/bin
|
/bin
|
||||||
/.cache
|
/.cache
|
||||||
|
/.idea
|
||||||
|
|||||||
@@ -1,6 +1,22 @@
|
|||||||
# DeathMessages
|
# DeathMessages
|
||||||
Better Death Messages on MCBE
|
Better Death Messages on MCBE
|
||||||
|
|
||||||
|
|
||||||
|
## Dependencies
|
||||||
|
|
||||||
|
|
||||||
|
### Required Dependency
|
||||||
|
|
||||||
|
`GMLIB`
|
||||||
|
|
||||||
|
|
||||||
|
### Optional Dependency
|
||||||
|
|
||||||
|
`ModAPI`
|
||||||
|
|
||||||
|
Loading *ModAPI* enables client-side translation.
|
||||||
|
That allows players to freely switch languages on their own.
|
||||||
|
|
||||||
# 开源许可
|
# 开源许可
|
||||||
## 源代码可用性
|
## 源代码可用性
|
||||||
- 您可以自由地获取、使用和修改本插件的源代码,无论是个人使用还是商业目的。
|
- 您可以自由地获取、使用和修改本插件的源代码,无论是个人使用还是商业目的。
|
||||||
|
|||||||
+6
-1
@@ -2,12 +2,17 @@
|
|||||||
"name": "${modName}",
|
"name": "${modName}",
|
||||||
"entry": "${modFile}",
|
"entry": "${modFile}",
|
||||||
"type": "native",
|
"type": "native",
|
||||||
"version": "0.13.1",
|
"version": "0.14.0",
|
||||||
"author": "GroupMountain",
|
"author": "GroupMountain",
|
||||||
"description": "Better Death Messages",
|
"description": "Better Death Messages",
|
||||||
"dependencies": [
|
"dependencies": [
|
||||||
{
|
{
|
||||||
"name": "GMLIB"
|
"name": "GMLIB"
|
||||||
}
|
}
|
||||||
|
],
|
||||||
|
"optionalDependencies": [
|
||||||
|
{
|
||||||
|
"name": "ModAPI"
|
||||||
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
+315
-91
@@ -1,143 +1,367 @@
|
|||||||
#include "Entry.h"
|
#include "Entry.h"
|
||||||
#include "GMLIB/Mod/Addons/CustomDamageCause.h"
|
|
||||||
#include "Global.h"
|
#include "ll/api/chrono/GameChrono.h"
|
||||||
#include "ll/api/event/player/PlayerConnectEvent.h"
|
#include "ll/api/memory/Hook.h"
|
||||||
#include "ll/api/event/player/PlayerDisconnectEvent.h"
|
#include "ll/api/service/Bedrock.h"
|
||||||
|
|
||||||
|
#include "mc/world/actor/ActorDamageSource.h"
|
||||||
|
#include "mc/world/actor/ActorDamageByActorSource.h"
|
||||||
|
#include "mc/world/actor/Actor.h"
|
||||||
|
#include "mc/world/actor/Mob.h"
|
||||||
|
#include "mc/world/level/Level.h"
|
||||||
|
|
||||||
|
//===============GMLIB 0.13.5 ActorDamageCause.cc===============
|
||||||
|
|
||||||
|
phmap::flat_hash_map<int64, float> mFallHeightMap;
|
||||||
|
phmap::flat_hash_map<int64, ActorUniqueID> mHurtByEntityMap;
|
||||||
|
phmap::flat_hash_map<int, std::string_view> mVanillaCauseMessage;
|
||||||
|
phmap::flat_hash_map<SharedTypes::Legacy::ActorDamageCause, phmap::flat_hash_map<std::string_view, std::string_view>> mHardCodedDeathMessage;
|
||||||
|
bool isCrystal = false;
|
||||||
|
|
||||||
|
std::string getCause(SharedTypes::Legacy::ActorDamageCause cause) {
|
||||||
|
auto id = (int)cause;
|
||||||
|
if (mVanillaCauseMessage.count(id)){return std::string(mVanillaCauseMessage[id]);}
|
||||||
|
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
Actor* getDamagingEntity(ActorDamageSource* ads) {
|
||||||
|
auto id = ads->getDamagingEntityUniqueID();
|
||||||
|
return ll::service::getLevel()->fetchEntity(id,true);
|
||||||
|
}
|
||||||
|
|
||||||
|
// %entity.warden.name
|
||||||
|
std::string getResourcePackKey(std::string const& name, Actor* ac) {
|
||||||
|
if (ac->hasCategory(ActorCategory::Player)){return name;}
|
||||||
|
|
||||||
|
auto type = ac->getTypeName();
|
||||||
|
ll::utils::string_utils::replaceAll(type, "minecraft:", "");
|
||||||
|
std::string res = "%entity." + type + ".name";
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 构造死亡信息输出
|
||||||
|
DeathMessageResult makeDeathMessage(
|
||||||
|
int cause,
|
||||||
|
DeathMessageResult& deathMessage,
|
||||||
|
std::string& name,
|
||||||
|
Actor* killer,
|
||||||
|
std::string& weaponName,
|
||||||
|
bool isEscaping,
|
||||||
|
bool isHardCodedMessage = false
|
||||||
|
) {
|
||||||
|
// 自定义类型构造
|
||||||
|
if (cause >= 35||mVanillaCauseMessage.count(cause) || isHardCodedMessage) {
|
||||||
|
std::string msg = "death.attack.damageCause.item";
|
||||||
|
ll::utils::string_utils::replaceAll(msg, "damageCause", getCause(SharedTypes::Legacy::ActorDamageCause(cause)));
|
||||||
|
if (isHardCodedMessage) {
|
||||||
|
msg = deathMessage.first;}
|
||||||
|
|
||||||
|
// 没有武器名不使用.item结尾
|
||||||
|
if (weaponName.empty()) {
|
||||||
|
// 试图逃离 xx 使用.player
|
||||||
|
if (killer) {
|
||||||
|
if (isEscaping){ll::utils::string_utils::replaceAll(msg, ".item", ".player");}
|
||||||
|
|
||||||
|
} else {
|
||||||
|
ll::utils::string_utils::replaceAll(msg, ".item", "");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
DeathMessageResult res = {msg, {name}};
|
||||||
|
if (killer) {
|
||||||
|
if (killer->isPlayer()) {
|
||||||
|
res.second.push_back(((Player*)killer)->getRealName());
|
||||||
|
} else {
|
||||||
|
res.second.push_back(getResourcePackKey(name, killer));
|
||||||
|
}
|
||||||
|
auto weaponname = killer->getCarriedItem().getCustomName();
|
||||||
|
if (!weaponname.empty()) {
|
||||||
|
weaponname = "[§b§o" + weaponname + "§r]";
|
||||||
|
res.second.push_back(weaponname);
|
||||||
|
} else {
|
||||||
|
ll::utils::string_utils::replaceAll(res.first, ".item", "");
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// 如果没有击杀者和试图逃离,那么不可能使用 .player 结尾
|
||||||
|
ll::utils::string_utils::replaceAll(res.first, ".player", "");
|
||||||
|
}
|
||||||
|
if (!DeathMessages::Entry::getInstance().isResourceI18nLoaded) {
|
||||||
|
res.first=tr(res.first, res.second);
|
||||||
|
res.second = {};
|
||||||
|
}
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
// 未定义返回vanilla值
|
||||||
|
return deathMessage;
|
||||||
|
}
|
||||||
|
|
||||||
|
DeathMessageResult tryTranslateHardCodedFallingDeathMessage(
|
||||||
|
DeathMessageResult& deathMessage,
|
||||||
|
std::string& name,
|
||||||
|
Actor* killer,
|
||||||
|
std::string& directKiller,
|
||||||
|
std::string& weaponName,
|
||||||
|
bool isEscaping,
|
||||||
|
int64 deadUniqueId
|
||||||
|
) {
|
||||||
|
if (!directKiller.empty()) {
|
||||||
|
deathMessage.first = "death.fell.finish.item";
|
||||||
|
}
|
||||||
|
// 低处
|
||||||
|
else if (deathMessage.first == "death.attack.fall") {
|
||||||
|
deathMessage.first = "death.attack.fall.item";
|
||||||
|
}
|
||||||
|
// 高处
|
||||||
|
else if (deathMessage.first == "death.fell.accident.generic") {
|
||||||
|
// 试图逃离而亡
|
||||||
|
if (killer) {
|
||||||
|
std::string weapon = killer->getCarriedItem().getCustomName();
|
||||||
|
if (!weapon.empty()) {
|
||||||
|
deathMessage.first = "death.fell.assist.item";
|
||||||
|
} else {
|
||||||
|
deathMessage.first = "death.fell.assist";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// 超高
|
||||||
|
else if (mFallHeightMap[deadUniqueId] >= 100) {
|
||||||
|
deathMessage.first = "death.fell.killer";
|
||||||
|
} else {
|
||||||
|
deathMessage.first = "death.fell.accident.generic";
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
deathMessage.first = "death.attack.generic";
|
||||||
|
}
|
||||||
|
return makeDeathMessage((int)SharedTypes::Legacy::ActorDamageCause::Fall, deathMessage, name, killer, weaponName, false, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::optional<DeathMessageResult> tryTranslateHardCodedDeathMessage(
|
||||||
|
SharedTypes::Legacy::ActorDamageCause cause,
|
||||||
|
DeathMessageResult& deathMessage,
|
||||||
|
std::string& name,
|
||||||
|
Actor* killer,
|
||||||
|
std::string& directKiller,
|
||||||
|
std::string& weaponName,
|
||||||
|
bool isEscaping,
|
||||||
|
int64 deadUniqueId
|
||||||
|
) {
|
||||||
|
switch (cause) {
|
||||||
|
// 硬编码摔死信息
|
||||||
|
case SharedTypes::Legacy::ActorDamageCause::Fall: {
|
||||||
|
return tryTranslateHardCodedFallingDeathMessage(
|
||||||
|
deathMessage,
|
||||||
|
name,
|
||||||
|
killer,
|
||||||
|
directKiller,
|
||||||
|
weaponName,
|
||||||
|
isEscaping,
|
||||||
|
deadUniqueId
|
||||||
|
);
|
||||||
|
}
|
||||||
|
// 硬编码爆炸信息
|
||||||
|
case SharedTypes::Legacy::ActorDamageCause::BlockExplosion: {
|
||||||
|
if (!isCrystal) {
|
||||||
|
deathMessage.first = "death.attack.badRespawnPoint.message";
|
||||||
|
} else {
|
||||||
|
deathMessage.first = "death.attack.explosion.item";
|
||||||
|
}
|
||||||
|
return makeDeathMessage((int)cause, deathMessage, name, killer, weaponName, isEscaping, true);
|
||||||
|
}
|
||||||
|
case SharedTypes::Legacy::ActorDamageCause::Contact: {
|
||||||
|
switch (ll::hash_utils::doHash(deathMessage.first)) {
|
||||||
|
case ll::hash_utils::doHash("death.attack.cactus"):
|
||||||
|
deathMessage.first = "death.attack.cactus.item";
|
||||||
|
break;
|
||||||
|
case ll::hash_utils::doHash("death.attack.sweetBerry"):
|
||||||
|
deathMessage.first = "death.attack.sweetBerry.item";
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
deathMessage.first = "death.attack.generic.item";
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return makeDeathMessage((int)cause, deathMessage, name, killer, weaponName, isEscaping, true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (mHardCodedDeathMessage.contains(cause)) {
|
||||||
|
if (directKiller.empty()) {
|
||||||
|
directKiller = "empty";
|
||||||
|
}
|
||||||
|
if (mHardCodedDeathMessage[cause].contains(directKiller)) {
|
||||||
|
deathMessage.first = std::string(mHardCodedDeathMessage[cause][directKiller]);
|
||||||
|
return makeDeathMessage((int)cause, deathMessage, name, killer, weaponName, isEscaping, true);
|
||||||
|
} else if (mHardCodedDeathMessage[cause].contains("all")) {
|
||||||
|
deathMessage.first = std::string(mHardCodedDeathMessage[cause]["all"]);
|
||||||
|
return makeDeathMessage((int)cause, deathMessage, name, killer, weaponName, isEscaping, true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
DeathMessageResult translateDeathMessage(DeathMessageResult origin, std::string name, Actor* dead, ActorDamageSource* ads) {
|
||||||
|
name = getResourcePackKey(name, dead);
|
||||||
|
if (origin.first.length() > 65565) {
|
||||||
|
return {"death.attack.even_more_magic", {name}};
|
||||||
|
}
|
||||||
|
auto damageCause = ads->mCause; // 伤害类型
|
||||||
|
Actor* killer = nullptr; // 击杀者
|
||||||
|
std::string directKiller; // 直接击杀实体
|
||||||
|
std::string weaponName; // 是否持有武器
|
||||||
|
bool isEscaping = false;
|
||||||
|
int64 uid = dead->getOrCreateUniqueID().rawID;
|
||||||
|
if (ads->isEntitySource()) {
|
||||||
|
directKiller = getDamagingEntity(ads)->getTypeName();
|
||||||
|
if (ads->isChildEntitySource()) {
|
||||||
|
killer = getDamagingEntity(ads)->getOwner();
|
||||||
|
} else {
|
||||||
|
killer = getDamagingEntity(ads);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (mHurtByEntityMap.count(uid)) {
|
||||||
|
if (killer == nullptr) {
|
||||||
|
killer = ll::service::getLevel()->fetchEntity(mHurtByEntityMap[uid],true);
|
||||||
|
|
||||||
|
}
|
||||||
|
isEscaping = true;
|
||||||
|
}
|
||||||
|
if (killer != nullptr) {
|
||||||
|
weaponName = killer->getCarriedItem().getCustomName();
|
||||||
|
}
|
||||||
|
// Vanilla的硬编码死亡信息类型
|
||||||
|
auto result =
|
||||||
|
tryTranslateHardCodedDeathMessage(damageCause, origin, name, killer, directKiller, weaponName, isEscaping, uid);
|
||||||
|
if (result.has_value()) {
|
||||||
|
return result.value();
|
||||||
|
}
|
||||||
|
return makeDeathMessage((int)damageCause, origin, name, killer, weaponName, isEscaping);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool setVanillaCauseMessage(SharedTypes::Legacy::ActorDamageCause cause, std::string_view msg) {
|
||||||
|
auto id = (int)cause;
|
||||||
|
if (!mVanillaCauseMessage.count(id)) {
|
||||||
|
mVanillaCauseMessage[id] = msg;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool registerCustomDeathMessage(
|
||||||
|
SharedTypes::Legacy::ActorDamageCause cause,
|
||||||
|
std::string_view message,
|
||||||
|
std::string_view killerType
|
||||||
|
) {
|
||||||
|
if (mHardCodedDeathMessage.contains(cause)) {
|
||||||
|
if (mHardCodedDeathMessage[cause].contains(killerType)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
mHardCodedDeathMessage[cause][killerType] = message;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
//===============Copy finish===============
|
||||||
|
|
||||||
|
|
||||||
void RegisterDamageDefinition() {
|
void RegisterDamageDefinition() {
|
||||||
GMLIB::Mod::DamageCause::DamageCause::setCustomDamageCauseEnabled();
|
setVanillaCauseMessage(SharedTypes::Legacy::ActorDamageCause::Anvil, "anvil");
|
||||||
GMLIB::Mod::DamageCause::DamageCause::setVanillaCauseMessage(ActorDamageCause::Anvil, "anvil");
|
setVanillaCauseMessage(SharedTypes::Legacy::ActorDamageCause::EntityAttack, "mob");
|
||||||
GMLIB::Mod::DamageCause::DamageCause::setVanillaCauseMessage(ActorDamageCause::EntityAttack, "mob");
|
setVanillaCauseMessage(SharedTypes::Legacy::ActorDamageCause::RamAttack, "mob");
|
||||||
GMLIB::Mod::DamageCause::DamageCause::setVanillaCauseMessage(ActorDamageCause::RamAttack, "mob");
|
setVanillaCauseMessage(SharedTypes::Legacy::ActorDamageCause::Drowning, "drown");
|
||||||
GMLIB::Mod::DamageCause::DamageCause::setVanillaCauseMessage(ActorDamageCause::Drowning, "drown");
|
setVanillaCauseMessage(SharedTypes::Legacy::ActorDamageCause::FallingBlock, "fallingBlock");
|
||||||
GMLIB::Mod::DamageCause::DamageCause::setVanillaCauseMessage(ActorDamageCause::FallingBlock, "fallingBlock");
|
setVanillaCauseMessage(SharedTypes::Legacy::ActorDamageCause::Fire, "inFire");
|
||||||
GMLIB::Mod::DamageCause::DamageCause::setVanillaCauseMessage(ActorDamageCause::Fire, "inFire");
|
setVanillaCauseMessage(SharedTypes::Legacy::ActorDamageCause::FireTick, "onFire");
|
||||||
GMLIB::Mod::DamageCause::DamageCause::setVanillaCauseMessage(ActorDamageCause::FireTick, "onFire");
|
setVanillaCauseMessage(SharedTypes::Legacy::ActorDamageCause::Fireworks, "fireworks");
|
||||||
GMLIB::Mod::DamageCause::DamageCause::setVanillaCauseMessage(ActorDamageCause::Fireworks, "fireworks");
|
setVanillaCauseMessage(SharedTypes::Legacy::ActorDamageCause::FlyIntoWall, "flyIntoWall");
|
||||||
GMLIB::Mod::DamageCause::DamageCause::setVanillaCauseMessage(ActorDamageCause::FlyIntoWall, "flyIntoWall");
|
setVanillaCauseMessage(SharedTypes::Legacy::ActorDamageCause::Freezing, "freeze");
|
||||||
GMLIB::Mod::DamageCause::DamageCause::setVanillaCauseMessage(ActorDamageCause::Freezing, "freeze");
|
setVanillaCauseMessage(SharedTypes::Legacy::ActorDamageCause::Lava, "lava");
|
||||||
GMLIB::Mod::DamageCause::DamageCause::setVanillaCauseMessage(ActorDamageCause::Lava, "lava");
|
setVanillaCauseMessage(SharedTypes::Legacy::ActorDamageCause::Lightning, "lightningBolt");
|
||||||
GMLIB::Mod::DamageCause::DamageCause::setVanillaCauseMessage(ActorDamageCause::Lightning, "lightningBolt");
|
setVanillaCauseMessage(SharedTypes::Legacy::ActorDamageCause::Wither, "wither");
|
||||||
GMLIB::Mod::DamageCause::DamageCause::setVanillaCauseMessage(ActorDamageCause::Wither, "wither");
|
setVanillaCauseMessage(SharedTypes::Legacy::ActorDamageCause::Magic, "indirectMagic");
|
||||||
GMLIB::Mod::DamageCause::DamageCause::setVanillaCauseMessage(ActorDamageCause::Magic, "indirectMagic");
|
setVanillaCauseMessage(SharedTypes::Legacy::ActorDamageCause::Magma, "hotFloor");
|
||||||
GMLIB::Mod::DamageCause::DamageCause::setVanillaCauseMessage(ActorDamageCause::Magma, "hotFloor");
|
setVanillaCauseMessage(SharedTypes::Legacy::ActorDamageCause::Stalactite, "stalactite");
|
||||||
GMLIB::Mod::DamageCause::DamageCause::setVanillaCauseMessage(ActorDamageCause::Stalactite, "stalactite");
|
setVanillaCauseMessage(SharedTypes::Legacy::ActorDamageCause::Stalagmite, "stalagmite");
|
||||||
GMLIB::Mod::DamageCause::DamageCause::setVanillaCauseMessage(ActorDamageCause::Stalagmite, "stalagmite");
|
setVanillaCauseMessage(SharedTypes::Legacy::ActorDamageCause::Starve, "starve");
|
||||||
GMLIB::Mod::DamageCause::DamageCause::setVanillaCauseMessage(ActorDamageCause::Starve, "starve");
|
setVanillaCauseMessage(SharedTypes::Legacy::ActorDamageCause::Suffocation, "inWall");
|
||||||
GMLIB::Mod::DamageCause::DamageCause::setVanillaCauseMessage(ActorDamageCause::Suffocation, "inWall");
|
setVanillaCauseMessage(SharedTypes::Legacy::ActorDamageCause::SonicBoom, "sonicBoom");
|
||||||
GMLIB::Mod::DamageCause::DamageCause::setVanillaCauseMessage(ActorDamageCause::SonicBoom, "sonicBoom");
|
setVanillaCauseMessage(SharedTypes::Legacy::ActorDamageCause::Void, "outOfWorld");
|
||||||
GMLIB::Mod::DamageCause::DamageCause::setVanillaCauseMessage(ActorDamageCause::Void, "outOfWorld");
|
setVanillaCauseMessage(SharedTypes::Legacy::ActorDamageCause::SelfDestruct, "genericKill");
|
||||||
GMLIB::Mod::DamageCause::DamageCause::setVanillaCauseMessage(ActorDamageCause::SelfDestruct, "genericKill");
|
setVanillaCauseMessage(SharedTypes::Legacy::ActorDamageCause::Projectile, "thrown");
|
||||||
GMLIB::Mod::DamageCause::DamageCause::setVanillaCauseMessage(ActorDamageCause::Projectile, "thrown");
|
setVanillaCauseMessage(SharedTypes::Legacy::ActorDamageCause::Thorns, "thorns");
|
||||||
GMLIB::Mod::DamageCause::DamageCause::setVanillaCauseMessage(ActorDamageCause::Thorns, "thorns");
|
registerCustomDeathMessage(
|
||||||
GMLIB::Mod::DamageCause::DamageCause::registerCustomDeathMessage(
|
SharedTypes::Legacy::ActorDamageCause::Projectile,
|
||||||
ActorDamageCause::Projectile,
|
|
||||||
"death.attack.fireball.item",
|
"death.attack.fireball.item",
|
||||||
"minecraft:small_fireball"
|
"minecraft:small_fireball"
|
||||||
);
|
);
|
||||||
GMLIB::Mod::DamageCause::DamageCause::registerCustomDeathMessage(
|
registerCustomDeathMessage(
|
||||||
ActorDamageCause::Projectile,
|
SharedTypes::Legacy::ActorDamageCause::Projectile,
|
||||||
"death.attack.trident.item",
|
"death.attack.trident.item",
|
||||||
"minecraft:thrown_trident"
|
"minecraft:thrown_trident"
|
||||||
);
|
);
|
||||||
GMLIB::Mod::DamageCause::DamageCause::registerCustomDeathMessage(
|
registerCustomDeathMessage(
|
||||||
ActorDamageCause::Projectile,
|
SharedTypes::Legacy::ActorDamageCause::Projectile,
|
||||||
"death.attack.spit",
|
"death.attack.spit",
|
||||||
"minecraft:llama_spit"
|
"minecraft:llama_spit"
|
||||||
);
|
);
|
||||||
GMLIB::Mod::DamageCause::DamageCause::registerCustomDeathMessage(
|
registerCustomDeathMessage(
|
||||||
ActorDamageCause::Projectile,
|
SharedTypes::Legacy::ActorDamageCause::Projectile,
|
||||||
"death.attack.bullet",
|
"death.attack.bullet",
|
||||||
"minecraft:shulker_bullet"
|
"minecraft:shulker_bullet"
|
||||||
);
|
);
|
||||||
GMLIB::Mod::DamageCause::DamageCause::registerCustomDeathMessage(
|
registerCustomDeathMessage(
|
||||||
ActorDamageCause::Projectile,
|
SharedTypes::Legacy::ActorDamageCause::Projectile,
|
||||||
"death.attack.arrow.item",
|
"death.attack.arrow.item",
|
||||||
"minecraft:arrow"
|
"minecraft:arrow"
|
||||||
);
|
);
|
||||||
GMLIB::Mod::DamageCause::DamageCause::registerCustomDeathMessage(
|
registerCustomDeathMessage(
|
||||||
ActorDamageCause::Projectile,
|
SharedTypes::Legacy::ActorDamageCause::Projectile,
|
||||||
"death.attack.explosion.player",
|
"death.attack.explosion.player",
|
||||||
"minecraft:fireball"
|
"minecraft:fireball"
|
||||||
);
|
);
|
||||||
GMLIB::Mod::DamageCause::DamageCause::registerCustomDeathMessage(
|
registerCustomDeathMessage(
|
||||||
ActorDamageCause::Projectile,
|
SharedTypes::Legacy::ActorDamageCause::Projectile,
|
||||||
"death.attack.mob",
|
"death.attack.mob",
|
||||||
"minecraft:breeze_wind_charge_projectile"
|
"minecraft:breeze_wind_charge_projectile"
|
||||||
);
|
);
|
||||||
GMLIB::Mod::DamageCause::DamageCause::registerCustomDeathMessage(
|
registerCustomDeathMessage(
|
||||||
ActorDamageCause::Magic,
|
SharedTypes::Legacy::ActorDamageCause::Magic,
|
||||||
"death.attack.magic",
|
"death.attack.magic",
|
||||||
"empty"
|
"empty"
|
||||||
);
|
);
|
||||||
GMLIB::Mod::DamageCause::DamageCause::registerCustomDeathMessage(
|
registerCustomDeathMessage(
|
||||||
ActorDamageCause::SonicBoom,
|
SharedTypes::Legacy::ActorDamageCause::SonicBoom,
|
||||||
"death.attack.sonicBoom",
|
"death.attack.sonicBoom",
|
||||||
"minecraft:warden"
|
"minecraft:warden"
|
||||||
);
|
);
|
||||||
GMLIB::Mod::DamageCause::DamageCause::registerCustomDeathMessage(
|
registerCustomDeathMessage(
|
||||||
ActorDamageCause::Thorns,
|
SharedTypes::Legacy::ActorDamageCause::Thorns,
|
||||||
"death.attack.generic",
|
"death.attack.generic",
|
||||||
"empty"
|
"empty"
|
||||||
);
|
);
|
||||||
GMLIB::Mod::DamageCause::DamageCause::registerCustomDeathMessage(
|
registerCustomDeathMessage(
|
||||||
ActorDamageCause::EntityExplosion,
|
SharedTypes::Legacy::ActorDamageCause::EntityExplosion,
|
||||||
"death.attack.explosion.player",
|
"death.attack.explosion.player",
|
||||||
"all"
|
"all"
|
||||||
);
|
);
|
||||||
GMLIB::Mod::DamageCause::DamageCause::registerCustomDeathMessage(
|
registerCustomDeathMessage(
|
||||||
ActorDamageCause::EntityExplosion,
|
SharedTypes::Legacy::ActorDamageCause::EntityExplosion,
|
||||||
"minecraft:wither_skull",
|
"minecraft:wither_skull",
|
||||||
"death.attack.witherSkull.item"
|
"death.attack.witherSkull.item"
|
||||||
);
|
);
|
||||||
GMLIB::Mod::DamageCause::DamageCause::registerCustomDeathMessage(
|
registerCustomDeathMessage(
|
||||||
ActorDamageCause::EntityExplosion,
|
SharedTypes::Legacy::ActorDamageCause::EntityExplosion,
|
||||||
"minecraft:wither_skull_dangerous",
|
"minecraft:wither_skull_dangerous",
|
||||||
"death.attack.witherSkull.item"
|
"death.attack.witherSkull.item"
|
||||||
);
|
);
|
||||||
GMLIB::Mod::DamageCause::DamageCause::registerCustomDeathMessage(
|
registerCustomDeathMessage(
|
||||||
ActorDamageCause::EntityAttack,
|
SharedTypes::Legacy::ActorDamageCause::EntityAttack,
|
||||||
"minecraft:player",
|
"minecraft:player",
|
||||||
"death.attack.player.item"
|
"death.attack.player.item"
|
||||||
);
|
);
|
||||||
GMLIB::Mod::DamageCause::DamageCause::registerCustomDeathMessage(
|
registerCustomDeathMessage(
|
||||||
ActorDamageCause::EntityAttack,
|
SharedTypes::Legacy::ActorDamageCause::EntityAttack,
|
||||||
"minecraft:bee",
|
"minecraft:bee",
|
||||||
"death.attack.sting.item"
|
"death.attack.sting.item"
|
||||||
);
|
);
|
||||||
GMLIB::Mod::DamageCause::DamageCause::registerCustomDeathMessage(
|
registerCustomDeathMessage(
|
||||||
ActorDamageCause::RamAttack,
|
SharedTypes::Legacy::ActorDamageCause::RamAttack,
|
||||||
"minecraft:player",
|
"minecraft:player",
|
||||||
"death.attack.player.item"
|
"death.attack.player.item"
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ListenEvents() {
|
|
||||||
auto& config = DeathMessages::Entry::getInstance().getConfig();
|
|
||||||
auto& eventBus = ll::event::EventBus::getInstance();
|
|
||||||
if (config.ConsoleLog.JoinMessage) {
|
|
||||||
eventBus.emplaceListener<ll::event::player::PlayerConnectEvent>([](ll::event::player::PlayerConnectEvent& ev) {
|
|
||||||
infoLogger->info(fmt::format(fg(fmt::color::yellow), tr("multiplayer.player.joined", {ev.self().getName()}))
|
|
||||||
);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
if (config.ConsoleLog.LeftMessage) {
|
|
||||||
eventBus.emplaceListener<ll::event::player::PlayerDisconnectEvent>(
|
|
||||||
[](ll::event::player::PlayerDisconnectEvent& ev) {
|
|
||||||
infoLogger->info(
|
|
||||||
fmt::format(fg(fmt::color::yellow), tr("multiplayer.player.left", {ev.self().getName()}))
|
|
||||||
);
|
|
||||||
}
|
|
||||||
);
|
|
||||||
}
|
|
||||||
if (config.ConsoleLog.DeathMessage) {
|
|
||||||
eventBus.emplaceListener<GMLIB::Event::EntityEvent::DeathMessageAfterEvent>(
|
|
||||||
[](GMLIB::Event::EntityEvent::DeathMessageAfterEvent& ev) {
|
|
||||||
auto msg = ev.getDeathMessage();
|
|
||||||
auto info = tr(msg.first, msg.second);
|
|
||||||
deathLogger->info(info);
|
|
||||||
ev.getDeathMessage() = {info, msg.second};
|
|
||||||
}
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
+53
-16
@@ -2,11 +2,28 @@
|
|||||||
#include "Global.h"
|
#include "Global.h"
|
||||||
#include "Language.h"
|
#include "Language.h"
|
||||||
|
|
||||||
|
#include "ll/api/Config.h"
|
||||||
|
#include "ll/api/data/IndirectValue.h"
|
||||||
|
#include "ll/api/io/PatternFormatter.h"
|
||||||
|
#include "ll/api/io/Logger.h"
|
||||||
|
#include "ll/api/io/LoggerRegistry.h"
|
||||||
|
#include "ll/api/io/FileSink.h"
|
||||||
|
#include "ll/api/mod/Mod.h"
|
||||||
|
#include "ll/api/mod/ModManagerRegistry.h"
|
||||||
|
#include "ll/api/mod/RegisterHelper.h"
|
||||||
|
#include "ll/api/service/Bedrock.h"
|
||||||
|
|
||||||
|
#include "gmlib/gm/i18n/LangI18n.h"
|
||||||
|
#include "gmlib/gm/i18n/ResourceI18n.h"
|
||||||
|
|
||||||
ll::io::LoggerRegistry& loggerRegistry = ll::io::LoggerRegistry::getInstance();
|
ll::io::LoggerRegistry& loggerRegistry = ll::io::LoggerRegistry::getInstance();
|
||||||
std::shared_ptr<ll::io::Logger> logger = loggerRegistry.getOrCreate(MOD_NAME);
|
std::shared_ptr<ll::io::Logger> logger = loggerRegistry.getOrCreate(MOD_NAME);
|
||||||
std::shared_ptr<ll::io::Logger> deathLogger = loggerRegistry.getOrCreate("Death");
|
std::shared_ptr<ll::io::Logger> deathLogger = loggerRegistry.getOrCreate("Death");
|
||||||
std::shared_ptr<ll::io::Logger> infoLogger = loggerRegistry.getOrCreate("Server");
|
std::shared_ptr<ll::io::Logger> infoLogger = loggerRegistry.getOrCreate("Server");
|
||||||
|
extern void uninstallHooks();
|
||||||
|
extern void RegisterDamageDefinition();
|
||||||
|
extern void uninstallEventListeners();
|
||||||
|
extern void ListenEvents();
|
||||||
|
|
||||||
namespace DeathMessages {
|
namespace DeathMessages {
|
||||||
|
|
||||||
@@ -16,25 +33,30 @@ Entry& Entry::getInstance() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool Entry::load() {
|
bool Entry::load() {
|
||||||
|
isResourceI18nLoaded=false;
|
||||||
|
|
||||||
mConfig.emplace();
|
mConfig.emplace();
|
||||||
if (!ll::config::loadConfig(*mConfig, getSelf().getConfigDir() / u8"config.json")) {
|
if (!ll::config::loadConfig(*mConfig, getSelf().getConfigDir() / u8"config.json")) {
|
||||||
ll::config::saveConfig(*mConfig, getSelf().getConfigDir() / u8"config.json");
|
ll::config::saveConfig(*mConfig, getSelf().getConfigDir() / u8"config.json");
|
||||||
}
|
}
|
||||||
if (getConfig().ServerSideTranslation.Enabled) {
|
|
||||||
loadI18n();
|
|
||||||
} else {
|
|
||||||
loadResourcePack();
|
|
||||||
}
|
|
||||||
if (getConfig().FileLog.Enabled) {
|
if (getConfig().FileLog.Enabled) {
|
||||||
auto& path = getConfig().FileLog.Path;
|
auto& path = getConfig().FileLog.Path;
|
||||||
ll::Polymorphic<ll::io::PatternFormatter> polymorphicFormatter =
|
ll::Polymorphic<ll::io::PatternFormatter> polymorphicFormatter =
|
||||||
ll::makePolymorphic<ll::io::PatternFormatter>("[{3:.3%F %T.} {2}][{1}] {0}", false);
|
ll::makePolymorphic<ll::io::PatternFormatter>("[{3:.3%F %T.} {2}][{1}] {0}", false);
|
||||||
deathLogger->addSink(std::make_shared<ll::io::FileSink>(path, polymorphicFormatter));
|
deathLogger->addSink(std::make_shared<ll::io::FileSink>(path, polymorphicFormatter));
|
||||||
}
|
}
|
||||||
|
loadI18n();
|
||||||
|
if ((!getConfig().ServerSideTranslation.Enabled)&&ll::mod::ModManagerRegistry::getInstance().hasMod("ModAPI")) {
|
||||||
|
loadResourcePack();
|
||||||
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Entry::enable() {
|
bool Entry::enable() {
|
||||||
|
if (!ll::mod::ModManagerRegistry::getInstance().hasMod("ModAPI")) {
|
||||||
|
getSelf().getLogger().warn(tr("plugin.deathmessages.modapi.warn"));
|
||||||
|
}
|
||||||
RegisterDamageDefinition();
|
RegisterDamageDefinition();
|
||||||
ListenEvents();
|
ListenEvents();
|
||||||
return true;
|
return true;
|
||||||
@@ -45,36 +67,51 @@ bool Entry::disable() { return true; }
|
|||||||
bool Entry::unload() {
|
bool Entry::unload() {
|
||||||
mConfig.reset();
|
mConfig.reset();
|
||||||
mI18n.reset();
|
mI18n.reset();
|
||||||
|
uninstallHooks();
|
||||||
|
loggerRegistry.erase(MOD_NAME);
|
||||||
|
loggerRegistry.erase("Death");
|
||||||
|
loggerRegistry.erase("Server");
|
||||||
// getInstance().reset();
|
// getInstance().reset();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
Config& Entry::getConfig() { return mConfig.value(); }
|
Config& Entry::getConfig() { return mConfig.value(); }
|
||||||
|
|
||||||
std::optional<GMLIB::Files::I18n::LangI18n> Entry::getI18n() { return mI18n; }
|
gmlib::i18n::LangI18n& Entry::getI18n() {
|
||||||
|
return *mI18n;
|
||||||
|
}
|
||||||
|
|
||||||
void Entry::loadI18n() {
|
void Entry::loadI18n() {
|
||||||
mI18n.emplace(getSelf().getLangDir(), getConfig().ServerSideTranslation.Language);
|
mI18n= std::make_unique<gmlib::i18n::LangI18n>(getSelf().getLangDir(), getConfig().ServerSideTranslation.Language);
|
||||||
mI18n->updateOrCreateLanguage("en_US", en_US);
|
mI18n->updateOrCreateLanguage("en_US", en_US);
|
||||||
mI18n->updateOrCreateLanguage("zh_CN", zh_CN);
|
mI18n->updateOrCreateLanguage("zh_CN", zh_CN);
|
||||||
mI18n->loadAllLanguages();
|
mI18n->loadAllLanguages();
|
||||||
mI18n->setDefaultLanguage("zh_CN");
|
mI18n->setDefaultLanguage("zh_CN");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void Entry::loadResourcePack() {
|
void Entry::loadResourcePack() {
|
||||||
GMLIB::Mod::VanillaFix::setFixI18nEnabled();
|
auto mResource = std::make_unique<gmlib::i18n::ResourceI18n>(getSelf().getModDir() / u8"lang", MOD_NAME, 0, 16, 1);
|
||||||
auto resource = GMLIB::Files::ResourceLanguage(getSelf().getModDir() / u8"resource", MOD_NAME, 0, 8, 0);
|
mResource->addLanguage("en_US", en_US);
|
||||||
resource.addLanguage("en_US", en_US);
|
mResource->addLanguage("zh_CN", zh_CN);
|
||||||
resource.addLanguage("zh_CN", zh_CN);
|
mResource->loadAllLanguages();
|
||||||
|
isResourceI18nLoaded=true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
} // namespace DeathMessages
|
} // namespace DeathMessages
|
||||||
|
|
||||||
LL_REGISTER_MOD(DeathMessages::Entry, DeathMessages::Entry::getInstance());
|
LL_REGISTER_MOD(DeathMessages::Entry, DeathMessages::Entry::getInstance());
|
||||||
|
|
||||||
std::string tr(std::string const& key, std::vector<std::string> const& params) {
|
std::string tr(std::string const& key, std::vector<std::string> const& params) {
|
||||||
if (auto i18n = DeathMessages::Entry::getInstance().getI18n()) {
|
auto& i18n = DeathMessages::Entry::getInstance().getI18n();
|
||||||
return i18n->get(key, params);
|
return i18n.get(key, params);
|
||||||
}
|
|
||||||
return ::I18nAPI::get(key, params);
|
|
||||||
|
return key;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+9
-2
@@ -2,6 +2,11 @@
|
|||||||
#include "Config.h"
|
#include "Config.h"
|
||||||
#include "Global.h"
|
#include "Global.h"
|
||||||
|
|
||||||
|
#include "ll/api/mod/Mod.h"
|
||||||
|
#include <ll/api/mod/NativeMod.h>
|
||||||
|
|
||||||
|
#include <gmlib/gm/i18n/LangI18n.h>
|
||||||
|
|
||||||
namespace DeathMessages {
|
namespace DeathMessages {
|
||||||
|
|
||||||
class Entry {
|
class Entry {
|
||||||
@@ -27,16 +32,18 @@ public:
|
|||||||
|
|
||||||
Config& getConfig();
|
Config& getConfig();
|
||||||
|
|
||||||
std::optional<GMLIB::Files::I18n::LangI18n> getI18n();
|
gmlib::i18n::LangI18n& getI18n();
|
||||||
|
|
||||||
void loadI18n();
|
void loadI18n();
|
||||||
|
|
||||||
void loadResourcePack();
|
void loadResourcePack();
|
||||||
|
|
||||||
|
|
||||||
|
bool isResourceI18nLoaded;
|
||||||
private:
|
private:
|
||||||
ll::mod::NativeMod& mSelf;
|
ll::mod::NativeMod& mSelf;
|
||||||
std::optional<Config> mConfig;
|
std::optional<Config> mConfig;
|
||||||
std::optional<GMLIB::Files::I18n::LangI18n> mI18n;
|
std::unique_ptr<gmlib::i18n::LangI18n> mI18n;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace DeathMessages
|
} // namespace DeathMessages
|
||||||
|
|||||||
+11
-4
@@ -1,13 +1,20 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
#include <include_all.h>
|
#include <ll/api/io/Logger.h>
|
||||||
|
|
||||||
|
#include <mc/legacy/ActorUniqueID.h>
|
||||||
|
#include <mc/world/actor/ActorDamageSource.h>
|
||||||
|
#include <parallel_hashmap/phmap.h>
|
||||||
|
|
||||||
#define MOD_NAME "DeathMessages"
|
#define MOD_NAME "DeathMessages"
|
||||||
|
|
||||||
extern std::shared_ptr<ll::io::Logger> logger;
|
extern std::shared_ptr<ll::io::Logger> logger;
|
||||||
extern std::shared_ptr<ll::io::Logger> deathLogger;
|
extern std::shared_ptr<ll::io::Logger> deathLogger;
|
||||||
extern std::shared_ptr<ll::io::Logger> infoLogger;
|
extern std::shared_ptr<ll::io::Logger> infoLogger;
|
||||||
|
extern phmap::flat_hash_map<int64, float> mFallHeightMap;
|
||||||
|
extern phmap::flat_hash_map<int64, ActorUniqueID> mHurtByEntityMap;
|
||||||
|
extern bool isCrystal;
|
||||||
|
|
||||||
extern std::string tr(std::string const& key, std::vector<std::string> const& data = {});
|
using DeathMessageResult = std::pair<std::string, std::vector<std::string>>;
|
||||||
|
|
||||||
extern void RegisterDamageDefinition();
|
extern DeathMessageResult translateDeathMessage(DeathMessageResult origin, std::string name, Actor* dead, ActorDamageSource* ads);
|
||||||
extern void ListenEvents();
|
extern std::string tr(std::string const& key, std::vector<std::string> const& params = {});
|
||||||
|
|||||||
+140
@@ -0,0 +1,140 @@
|
|||||||
|
#include "Entry.h"
|
||||||
|
#include "Global.h"
|
||||||
|
|
||||||
|
#include "ll/api/memory/Hook.h"
|
||||||
|
#include "ll/api/chrono/GameChrono.h"
|
||||||
|
#include "ll/api/thread/ThreadPoolExecutor.h"
|
||||||
|
|
||||||
|
#include "mc/world/actor/Mob.h"
|
||||||
|
#include "mc/world/actor/monster/EnderCrystal.h"
|
||||||
|
#include "mc/world/actor/ActorDamageSource.h"
|
||||||
|
#include "mc/world/actor/ActorDamageByActorSource.h"
|
||||||
|
#include "mc/world/actor/ActorDamageByBlockSource.h"
|
||||||
|
#include "mc/world/actor/ActorDamageByChildActorSource.h"
|
||||||
|
#include "mc/world/actor/ActorHurtResult.h"
|
||||||
|
#include "mc/world/actor/Actor.h"
|
||||||
|
|
||||||
|
#include <chrono>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
LL_AUTO_TYPE_INSTANCE_HOOK(
|
||||||
|
MobDieHook,
|
||||||
|
HookPriority::Normal,
|
||||||
|
Mob,
|
||||||
|
&Mob::$die,
|
||||||
|
void,
|
||||||
|
ActorDamageSource const& ads
|
||||||
|
) {
|
||||||
|
auto uid = getOrCreateUniqueID();
|
||||||
|
|
||||||
|
if (ads.mCause == SharedTypes::Legacy::ActorDamageCause::Fall) {
|
||||||
|
mFallHeightMap[uid.rawID] = getFallDistance();
|
||||||
|
}
|
||||||
|
if (hasCategory(ActorCategory::Player) || isTame()) {
|
||||||
|
if (mLastHurtByMobTime != 0) {
|
||||||
|
auto hm = getLastHurtByMob();
|
||||||
|
mHurtByEntityMap[uid.rawID] = hm->getOrCreateUniqueID();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
origin(ads);
|
||||||
|
|
||||||
|
auto& executor = ll::thread::ThreadPoolExecutor::getDefault();
|
||||||
|
auto callback = executor.executeAfter(
|
||||||
|
[] {
|
||||||
|
mHurtByEntityMap.clear();
|
||||||
|
mFallHeightMap.clear();
|
||||||
|
},
|
||||||
|
ll::chrono::game::ticks(1)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
LL_AUTO_TYPE_INSTANCE_HOOK(
|
||||||
|
CryatslHurtHook,
|
||||||
|
HookPriority::Normal,
|
||||||
|
EnderCrystal,
|
||||||
|
&EnderCrystal::$_hurt,
|
||||||
|
::ActorHurtResult,
|
||||||
|
ActorDamageSource const& a1,
|
||||||
|
float a2,
|
||||||
|
bool a3,
|
||||||
|
bool a4
|
||||||
|
) {
|
||||||
|
auto res = origin(a1, a2, a3, a4);
|
||||||
|
isCrystal = true;
|
||||||
|
auto& executor = ll::thread::ThreadPoolExecutor::getDefault();
|
||||||
|
auto callback = executor.executeAfter(
|
||||||
|
[] {
|
||||||
|
isCrystal = false;
|
||||||
|
},
|
||||||
|
ll::chrono::game::ticks(1)
|
||||||
|
);
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
LL_AUTO_TYPE_INSTANCE_HOOK(
|
||||||
|
ActorDamageHook,
|
||||||
|
HookPriority::Lowest,
|
||||||
|
ActorDamageSource,
|
||||||
|
&ActorDamageSource::$getDeathMessage,
|
||||||
|
DeathMessageResult,
|
||||||
|
std::string a1,
|
||||||
|
Actor* a2
|
||||||
|
) {
|
||||||
|
auto originl = origin(a1, a2);
|
||||||
|
auto res = translateDeathMessage(originl, a1, a2, this);
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
LL_AUTO_TYPE_INSTANCE_HOOK(
|
||||||
|
ActorDamageByActorHook,
|
||||||
|
HookPriority::Lowest,
|
||||||
|
ActorDamageByActorSource,
|
||||||
|
&ActorDamageByActorSource::$getDeathMessage,
|
||||||
|
DeathMessageResult,
|
||||||
|
std::string a1,
|
||||||
|
Actor* a2
|
||||||
|
) {
|
||||||
|
auto originl = origin(a1, a2);
|
||||||
|
auto res = translateDeathMessage(originl, a1, a2, this);
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
LL_AUTO_TYPE_INSTANCE_HOOK(
|
||||||
|
ActorDamageByBlockHook,
|
||||||
|
HookPriority::Lowest,
|
||||||
|
ActorDamageByBlockSource,
|
||||||
|
&ActorDamageByBlockSource::$getDeathMessage,
|
||||||
|
DeathMessageResult,
|
||||||
|
std::string a1,
|
||||||
|
Actor* a2
|
||||||
|
) {
|
||||||
|
auto originl = origin(a1, a2);
|
||||||
|
auto res = translateDeathMessage(originl, a1, a2, this);
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
LL_AUTO_TYPE_INSTANCE_HOOK(
|
||||||
|
ActorDamageByChildHook,
|
||||||
|
HookPriority::Lowest,
|
||||||
|
ActorDamageByChildActorSource,
|
||||||
|
&ActorDamageByChildActorSource::$getDeathMessage,
|
||||||
|
DeathMessageResult,
|
||||||
|
std::string a1,
|
||||||
|
Actor* a2
|
||||||
|
) {
|
||||||
|
auto originl = origin(a1, a2);
|
||||||
|
auto res = translateDeathMessage(originl, a1, a2, this);
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
void uninstallHooks() {
|
||||||
|
MobDieHook::unhook();
|
||||||
|
CryatslHurtHook::unhook();
|
||||||
|
ActorDamageHook::unhook();
|
||||||
|
ActorDamageByActorHook::unhook();
|
||||||
|
ActorDamageByBlockHook::unhook();
|
||||||
|
ActorDamageByChildHook::unhook();
|
||||||
|
}
|
||||||
+123
-109
@@ -35,6 +35,7 @@ death.attack.flyIntoWall.item=%1 felt the force of kinetic energy while trying t
|
|||||||
death.attack.generic=%1$s died
|
death.attack.generic=%1$s died
|
||||||
death.attack.generic.player=%1$s died from %2$s
|
death.attack.generic.player=%1$s died from %2$s
|
||||||
death.attack.indirectMagic=%1$s was killed by magic used by %2$s
|
death.attack.indirectMagic=%1$s was killed by magic used by %2$s
|
||||||
|
death.attack.indirectMagic.player=%1$s was killed by magic used by %2$s
|
||||||
death.attack.indirectMagic.item=%1$s was killed by %2$s using %3$s
|
death.attack.indirectMagic.item=%1$s was killed by %2$s using %3$s
|
||||||
death.attack.inFire=%1$s was consumed by fire
|
death.attack.inFire=%1$s was consumed by fire
|
||||||
death.attack.inFire.player=%1$s accidentally walked into fire while fighting %2$s
|
death.attack.inFire.player=%1$s accidentally walked into fire while fighting %2$s
|
||||||
@@ -72,8 +73,10 @@ death.attack.sweetBerry=%1$s was pricked to death by sweet berry bushes
|
|||||||
death.attack.sweetBerry.player=%1$s was pricked to death by sweet berry bushes while trying to escape %2$s
|
death.attack.sweetBerry.player=%1$s was pricked to death by sweet berry bushes while trying to escape %2$s
|
||||||
death.attack.sweetBerry.item=%1$s was pricked to death by sweet berry bushes while trying to escape %2$s holding %3$s
|
death.attack.sweetBerry.item=%1$s was pricked to death by sweet berry bushes while trying to escape %2$s holding %3$s
|
||||||
death.attack.thorns=%1$s was killed trying to hurt %2$s
|
death.attack.thorns=%1$s was killed trying to hurt %2$s
|
||||||
|
death.attack.thorns.player=%1$s was killed trying to hurt %2$s
|
||||||
death.attack.thorns.item=%1$s was killed by %3$s when trying to hurt %2$s
|
death.attack.thorns.item=%1$s was killed by %3$s when trying to hurt %2$s
|
||||||
death.attack.thrown=%1$s was pummeled by %2$s
|
death.attack.thrown=%1$s was pummeled by %2$s
|
||||||
|
death.attack.thrown.player=%1$s was pummeled by %2$s
|
||||||
death.attack.thrown.item=%1$s was pummeled by %2$s using %3$s
|
death.attack.thrown.item=%1$s was pummeled by %2$s using %3$s
|
||||||
death.attack.trident=%1$s was impaled by %2$s
|
death.attack.trident=%1$s was impaled by %2$s
|
||||||
death.attack.trident.item=%1$s was impaled by %2$s using %3$s
|
death.attack.trident.item=%1$s was impaled by %2$s using %3$s
|
||||||
@@ -84,6 +87,7 @@ death.attack.freeze=%1$s froze to death
|
|||||||
death.attack.freeze.player=%1$s was frozen to death by %2$s
|
death.attack.freeze.player=%1$s was frozen to death by %2$s
|
||||||
death.attack.freeze.item=%1$s was frozen to death by %2$s holding %3$s
|
death.attack.freeze.item=%1$s was frozen to death by %2$s holding %3$s
|
||||||
death.attack.sonicBoom=%1$s was obliterated by a sonic boom
|
death.attack.sonicBoom=%1$s was obliterated by a sonic boom
|
||||||
|
death.attack.sonicBoom.item=%1$s was obliterated by a sonic boom while trying to escape %2$s
|
||||||
death.attack.sonicBoom.player=%1$s was obliterated by a sonic boom while trying to escape %2$s
|
death.attack.sonicBoom.player=%1$s was obliterated by a sonic boom while trying to escape %2$s
|
||||||
death.attack.stalactite=%1$s was impaled by a falling stalactite
|
death.attack.stalactite=%1$s was impaled by a falling stalactite
|
||||||
death.attack.stalactite.player=%1$s was impaled by a falling stalactite while battling %2$s
|
death.attack.stalactite.player=%1$s was impaled by a falling stalactite while battling %2$s
|
||||||
@@ -107,6 +111,7 @@ death.fell.accident.generic=%1$s fell from a high place
|
|||||||
death.fell.assist=%1$s was doomed to fall by %2$s
|
death.fell.assist=%1$s was doomed to fall by %2$s
|
||||||
death.fell.assist.item=%1$s was doomed to fall by %2$s using %3$s
|
death.fell.assist.item=%1$s was doomed to fall by %2$s using %3$s
|
||||||
death.fell.finish=%1$s fell too far and was finished by %2$s
|
death.fell.finish=%1$s fell too far and was finished by %2$s
|
||||||
|
death.fell.finish.player=%1$s fell too far and was finished by %2$s
|
||||||
death.fell.finish.item=%1$s fell too far and was finished by %2$s using %3$s
|
death.fell.finish.item=%1$s fell too far and was finished by %2$s using %3$s
|
||||||
death.fell.killer=%1$s was doomed to fall
|
death.fell.killer=%1$s was doomed to fall
|
||||||
entity.area_effect_cloud.name=Area Effect Cloud
|
entity.area_effect_cloud.name=Area Effect Cloud
|
||||||
@@ -250,116 +255,124 @@ entity.breeze.name=Breeze
|
|||||||
entity.creaking.name=Creaking
|
entity.creaking.name=Creaking
|
||||||
multiplayer.player.joined=%s joined the game
|
multiplayer.player.joined=%s joined the game
|
||||||
multiplayer.player.left=%s left the game
|
multiplayer.player.left=%s left the game
|
||||||
|
plugin.deathmessages.modapi.warn=The optional Dependency plugin ModAPI is not loaded, so client-side translation is unavailable. Only server-side translation can be used.
|
||||||
)";
|
)";
|
||||||
|
|
||||||
std::string zh_CN = R"(
|
std::string zh_CN = R"(
|
||||||
death.attack.anvil=%1$s被坠落的铁砧压扁了
|
death.attack.anvil=%1$s 被坠落的铁砧压扁了
|
||||||
death.attack.anvil.player=%1$sz在与%2$s战斗时被坠落的铁砧压扁了
|
death.attack.anvil.player=%1$s 在与 %2$s 战斗时被坠落的铁砧压扁了
|
||||||
death.attack.anvil.item=%1$s在与持有%3$s的%2$s战斗时被坠落的铁砧压扁了
|
death.attack.anvil.item=%1$s 在与持有 %3$s 的 %2$s 战斗时被坠落的铁砧压扁了
|
||||||
death.attack.arrow=%1$s被%2$s射杀
|
death.attack.arrow=%1$s被 %2$s 射杀
|
||||||
death.attack.arrow.item=%1$s被%2$s用%3$s射杀
|
death.attack.arrow.item=%1$s 被 %2$s 用 %3$s 射杀
|
||||||
death.attack.bullet=%1$s被%2$s狙击了
|
death.attack.bullet=%1$s被 %2$s 狙击了
|
||||||
death.attack.cactus=%1$s被戳死了
|
death.attack.cactus=%1$s 被戳死了
|
||||||
death.attack.cactus.player=%1$s在试图逃离%2$s时撞上了仙人掌
|
death.attack.cactus.player=%1$s 在试图逃离 %2$s 时撞上了仙人掌
|
||||||
death.attack.cactus.item=%1$s在试图逃离持有%3$s的%2$s时撞上了仙人掌
|
death.attack.cactus.item=%1$s 在试图逃离持有 %3$s 的 %2$s 时撞上了仙人掌
|
||||||
death.attack.drown=%1$s淹死了
|
death.attack.drown=%1$s 淹死了
|
||||||
death.attack.drown.player=%1$s在试图逃离%2$s时淹死了
|
death.attack.drown.player=%1$s 在试图逃离 %2$s 时淹死了
|
||||||
death.attack.drown.item=%1$s在试图逃离持有%3$s的%2$s时淹死了
|
death.attack.drown.item=%1$s 在试图逃离持有 %3$s 的 %2$s 时淹死了
|
||||||
death.attack.explosion=%1$s爆炸了
|
death.attack.explosion=%1$s 爆炸了
|
||||||
death.attack.explosion.player=%1$s被%2$s炸死了
|
death.attack.explosion.player=%1$s 被 %2$s 炸死了
|
||||||
death.attack.explosion.item=%1$s被%2$s使用%3$s炸死了
|
death.attack.explosion.item=%1$s 被 %2$s 使用 %3$s 炸死了
|
||||||
death.attack.badRespawnPoint.message=%1$s被[刻意的游戏设计]杀死了
|
death.attack.badRespawnPoint.message=%1$s 被 [刻意的游戏设计] 杀死了
|
||||||
death.attack.fall=%1$s落地过猛
|
death.attack.fall=%1$s 落地过猛
|
||||||
death.attack.fall.player=%1$s在试图逃离%2$s时落地过猛
|
death.attack.fall.player=%1$s 在试图逃离 %2$s 时落地过猛
|
||||||
death.attack.fall.item=%1$s在试图逃离持有%3$s的%2$s时落地过猛
|
death.attack.fall.item=%1$s 在试图逃离持有 %3$s 的 %2$s 时落地过猛
|
||||||
death.attack.fallingBlock=%1$s被坠落的方块压扁了
|
death.attack.fallingBlock=%1$s 被坠落的方块压扁了
|
||||||
death.attack.fallingBlock.player=%1$sz在与%2$s战斗时被坠落的方块压扁了
|
death.attack.fallingBlock.player=%1$s 在与 %2$s 战斗时被坠落的方块压扁了
|
||||||
death.attack.fallingBlock.item=%1$s在与持有%3$s的%2$s战斗时被坠落的方块压扁了
|
death.attack.fallingBlock.item=%1$s 在与持有 %3$s 的 %2$s 战斗时被坠落的方块压扁了
|
||||||
death.attack.fireball=%1$s被%2$s用火球烧死了
|
death.attack.fireball=%1$s被 %2$s 用火球烧死了
|
||||||
death.attack.fireball.item=%1$s被%2$s用%3$s发射的火球烧死了
|
death.attack.fireball.item=%1$s被 %2$s 用 %3$s 发射的火球烧死了
|
||||||
death.attack.fireworks=%1$s随着一声巨响消失了
|
death.attack.fireworks=%1$s 随着一声巨响消失了
|
||||||
death.attack.fireworks.player=%1$s在与%2$s战斗时随着一声巨响消失了
|
death.attack.fireworks.player=%1$s 在与 %2$s 战斗时随着一声巨响消失了
|
||||||
death.attack.fireworks.item=%1$s随着%2$s用%3$s发射的烟花发出的巨响消失了
|
death.attack.fireworks.item=%1$s 随着 %2$s 用 %3$s 发射的烟花发出的巨响消失了
|
||||||
death.attack.flyIntoWall=%1$s感受到了动能
|
death.attack.flyIntoWall=%1$s 感受到了动能
|
||||||
death.attack.flyIntoWall.player=%1$s在试图逃离%2$s时感受到了动能
|
death.attack.flyIntoWall.player=%1$s 在试图逃离 %2$s 时感受到了动能
|
||||||
death.attack.flyIntoWall.item=%1$s在试图逃离持有%3$s的%2$s时感受到了动能
|
death.attack.flyIntoWall.item=%1$s 在试图逃离持有 %3$s 的 %2$s 时感受到了动能
|
||||||
death.attack.generic=%1$s死了
|
death.attack.generic=%1$s 死了
|
||||||
death.attack.generic.player=%1$s死于%2$s
|
death.attack.generic.player=%1$s 死于 %2$s
|
||||||
death.attack.indirectMagic=%1$s被%2$s使用的魔法杀死了
|
death.attack.indirectMagic=%1$s 被 %2$s 使用的魔法杀死了
|
||||||
death.attack.indirectMagic.item=%1$s被%2$s用%3$s杀死了
|
death.attack.indirectMagic.player=%1$s 被 %2$s 使用的魔法杀死了
|
||||||
death.attack.inFire=%1$s浴火焚身
|
death.attack.indirectMagic.item=%1$s 被 %2$s 用 %3$s 杀死了
|
||||||
death.attack.inFire.player=%1$s在与%2$s战斗时不慎走入了火中
|
death.attack.inFire=%1$s 浴火焚身
|
||||||
death.attack.inFire.item=%1$s在与持有%3$s的%2$s战斗时不慎走入了火中
|
death.attack.inFire.player=%1$s 在与 %2$s 战斗时不慎走入了火中
|
||||||
death.attack.inWall=%1$s在墙里窒息而亡
|
death.attack.inFire.item=%1$s 在与持有 %3$s 的 %2$s 战斗时不慎走入了火中
|
||||||
death.attack.inWall.player=%1$s在与%2$s战斗时在墙里窒息而亡
|
death.attack.inWall=%1$s 在墙里窒息而亡
|
||||||
death.attack.inWall.item=%1$s在与持有%3$s的%2$s战斗时在墙里窒息而亡
|
death.attack.inWall.player=%1$s 在与 %2$s 战斗时在墙里窒息而亡
|
||||||
death.attack.lava=%1$s试图在熔岩里游泳
|
death.attack.inWall.item=%1$s 在与持有 %3$s 的 %2$s 战斗时在墙里窒息而亡
|
||||||
death.attack.lava.player=%1$s在试图逃离%2$s时试图在熔岩里游泳
|
death.attack.lava=%1$s 试图在熔岩里游泳
|
||||||
death.attack.lava.item=%1$s在试图逃离持有%3$s的%2$s时试图在熔岩里游泳
|
death.attack.lava.player=%1$s 在试图逃离 %2$s 时试图在熔岩里游泳
|
||||||
death.attack.lightningBolt=%1$s被闪电击中
|
death.attack.lava.item=%1$s 在试图逃离持有 %3$s 的 %2$s 时试图在熔岩里游泳
|
||||||
death.attack.lightningBolt.player=%1$s在与%2$s战斗时被闪电击中
|
death.attack.lightningBolt=%1$s 被闪电击中
|
||||||
death.attack.lightningBolt.item=%1$s在与持有%3$s的%2$s战斗时被闪电击中
|
death.attack.lightningBolt.player=%1$s 在与 %2$s 战斗时被闪电击中
|
||||||
death.attack.magic=%1$s被魔法杀死了
|
death.attack.lightningBolt.item=%1$s 在与持有 %3$s 的 %2$s 战斗时被闪电击中
|
||||||
death.attack.hotFloor=%1$s发现地板是熔岩做的
|
death.attack.magic=%1$s 被魔法杀死了
|
||||||
death.attack.hotFloor.player=%1$s因%2$s而步入危险之地
|
death.attack.hotFloor=%1$s 发现地板是熔岩做的
|
||||||
death.attack.hotFloor.item=%1$s因持有%3$s的%2$s而步入危险之地
|
death.attack.hotFloor.player=%1$s 因 %2$s 而步入危险之地
|
||||||
death.attack.mob=%1$s被%2$s杀死了
|
death.attack.hotFloor.item=%1$s 因持有 %3$s 的 %2$s 而步入危险之地
|
||||||
death.attack.mob.item=%1$s被%2$s用%3$s杀死了
|
death.attack.mob=%1$s 被 %2$s 杀死了
|
||||||
death.attack.sting=%1$s被%2$s蛰死了
|
death.attack.mob.player=%1$s 被 %2$s 杀死了
|
||||||
death.attack.sting.item=%1$s被%2$s用%3$s蛰死了
|
death.attack.mob.item=%1$s 被 %2$s 用 %3$s 杀死了
|
||||||
death.attack.onFire=%1$s被烧死了
|
death.attack.sting=%1$s 被 %2$s 蛰死了
|
||||||
death.attack.onFire.player=%1$s在与%2$s战斗时被烤的酥脆
|
death.attack.sting.item=%1$s 被 %2$s 用 %3$s 蛰死了
|
||||||
death.attack.onFire.item=%1$s在与持有%3$s的%2$s战斗时被烤的酥脆
|
death.attack.onFire=%1$s 被烧死了
|
||||||
death.attack.outOfWorld=%1$s掉出了这个世界
|
death.attack.onFire.player=%1$s 在与 %2$s 战斗时被烤的酥脆
|
||||||
death.attack.outOfWorld.player=%1$s与%2$s不共戴天
|
death.attack.onFire.item=%1$s 在与持有 %3$s 的 %2$s 战斗时被烤的酥脆
|
||||||
death.attack.outOfWorld.item=%1$s与持有%3$s的%2$s不共戴天
|
death.attack.outOfWorld=%1$s 掉出了这个世界
|
||||||
death.attack.player=%1$s被%2$s杀死了
|
death.attack.outOfWorld.player=%1$s 与 %2$s 不共戴天
|
||||||
death.attack.player.item=%1$s被%2$s用%3$s杀死了
|
death.attack.outOfWorld.item=%1$s 与持有 %3$s 的 %2$s 不共戴天
|
||||||
death.attack.spit=%1$s被%2$s的口水淹死了
|
death.attack.player=%1$s 被 %2$s 杀死了
|
||||||
death.attack.starve=%1$s饿死了
|
death.attack.player.item=%1$s 被 %2$s 用 %3$s 杀死了
|
||||||
death.attack.starve.player=%1$s在与%2$s战斗时饿死了
|
death.attack.spit=%1$s 被 %2$s 的口水淹死了
|
||||||
death.attack.starve.item=%1$s在与持有%3$s的%2$s战斗时饿死了
|
death.attack.starve=%1$s 饿死了
|
||||||
death.attack.sweetBerry=%1$s被甜浆果丛刺死了
|
death.attack.starve.player=%1$s 在与 %2$s 战斗时饿死了
|
||||||
death.attack.sweetBerry.player=%1$s在试图逃离%2$s时被甜浆果丛刺死了
|
death.attack.starve.item=%1$s 在与持有 %3$s 的 %2$s 战斗时饿死了
|
||||||
death.attack.sweetBerry.item=%1$s在试图逃离持有%3$s的%2$s时被甜浆果丛刺死了
|
death.attack.sweetBerry=%1$s 被甜浆果丛刺死了
|
||||||
death.attack.thorns=%1$s在试图伤害%2$s时被杀
|
death.attack.sweetBerry.player=%1$s 在试图逃离 %2$s 时被甜浆果丛刺死了
|
||||||
death.attack.thorns.item=%1$s在试图伤害%2$s时被%3$s杀死
|
death.attack.sweetBerry.item=%1$s 在试图逃离持有 %3$s 的 %2$s 时被甜浆果丛刺死了
|
||||||
death.attack.thrown=%1$s被%2$s给砸死了
|
death.attack.thorns=%1$s 在试图伤害 %2$s
|
||||||
death.attack.thrown.item=%1$s被%2$s用%3$s给砸死了
|
death.attack.thorns.player=%1$s 在试图伤害 %2$s 时被杀
|
||||||
death.attack.trident=%1$s被%2$s刺穿了
|
death.attack.thorns.item=%1$s 在试图伤害 %2$s 时被 %3$s 杀死
|
||||||
death.attack.trident.item=%1$s被%2$s使用%3$s刺穿了
|
death.attack.thrown=%1$s 被 %2$s 给砸死了
|
||||||
death.attack.wither=%1$s凋零了
|
death.attack.thrown.player=%1$s 被 %2$s 给砸死了
|
||||||
death.attack.wither.player=%1$s在与%2$s战斗时凋零了
|
death.attack.thrown.item=%1$s 被 %2$s 用 %3$s 给砸死了
|
||||||
death.attack.wither.item=%1$s在与持有%3$s的%2$s战斗时凋零了
|
death.attack.trident=%1$s 被 %2$s 刺穿了
|
||||||
death.attack.freeze=%1$s被冻死了
|
death.attack.trident.item=%1$s 被 %2$s 使用 %3$s 刺穿了
|
||||||
death.attack.freeze.player=%1$s被%2$s冻死了
|
death.attack.wither=%1$s 凋零了
|
||||||
death.attack.freeze.item=%1$s被持有%3$s的%2$s冻死了
|
death.attack.wither.player=%1$s 在与 %2$s 战斗时凋零了
|
||||||
death.attack.sonicBoom=%1$s被一道音波尖啸抹除了
|
death.attack.wither.item=%1$s 在与持有 %3$s 的 %2$s 战斗时凋零了
|
||||||
death.attack.sonicBoom.player=%1$s在试图逃离%2$s时被一道音波尖啸抹除了
|
death.attack.freeze=%1$s 被冻死了
|
||||||
death.attack.stalactite=%1$s被坠落的钟乳石刺穿了
|
death.attack.freeze.player=%1$s 被 %2$s 冻死了
|
||||||
death.attack.stalactite.player=%1$s在与%2$s战斗时被坠落的钟乳石刺穿了
|
death.attack.freeze.item=%1$s 被持有 %3$s 的 %2$s 冻死了
|
||||||
death.attack.stalactite.item=%1$s在与持有%3$s的%2$s战斗时被坠落的钟乳石刺穿了
|
death.attack.sonicBoom=%1$s 被一道音波尖啸抹除了
|
||||||
death.attack.stalagmite=%1$s被石笋刺穿了
|
death.attack.sonicBoom.player=%1$s 在试图逃离 %2$s 时被一道音波尖啸抹除了
|
||||||
death.attack.stalagmite.player=%1$s在与%2$s战斗时被石笋刺穿了
|
death.attack.sonicBoom.item=%1$s 在试图逃离 %2$s 时被一道音波尖啸抹除了
|
||||||
death.attack.stalagmite.item=%1$s在与持有%3$s的%2$s战斗时被石笋刺穿了
|
death.attack.stalactite=%1$s 被坠落的钟乳石刺穿了
|
||||||
death.attack.witherSkull=%1$s被%2$s发射的头颅射杀
|
death.attack.stalactite.player=%1$s 在与 %2$s 战斗时被坠落的钟乳石刺穿了
|
||||||
death.attack.witherSkull.item=%1$s被%2$s用%3$s发射的头颅射杀
|
death.attack.stalactite.item=%1$s 在与持有 %3$s 的 %2$s 战斗时被坠落的钟乳石刺穿了
|
||||||
death.attack.even_more_magic=%1$s被不为人知的魔法杀死了
|
death.attack.stalagmite=%1$s 被石笋刺穿了
|
||||||
death.attack.genericKill=%1$s被杀死了
|
death.attack.stalagmite.player=%1$s 在与 %2$s 战斗时被石笋刺穿了
|
||||||
death.attack.genericKill.player=%1$s在与%2$s战斗时被杀死了
|
death.attack.stalagmite.item=%1$s 在与持有 %3$s 的 %2$s 战斗时被石笋刺穿了
|
||||||
death.attack.genericKill.item=%1$s在与持有%3$s的%2$s战斗时被杀死了
|
death.attack.witherSkull=%1$s 被 %2$s 发射的头颅射杀
|
||||||
death.attack.dragonBreath=%1$s被龙息烤熟了
|
death.attack.witherSkull.item=%1$s 被 %2$s 用 %3$s 发射的头颅射杀
|
||||||
death.attack.dragonBreath.player=%1$s被%2$s的龙息烤熟了
|
death.attack.even_more_magic=%1$s 被不为人知的魔法杀死了
|
||||||
death.attack.dryout=%1$s因脱水而死
|
death.attack.genericKill=%1$s 被杀死了
|
||||||
death.attack.dryout.player=%1$s在试图逃离%2$s时因脱水而死
|
death.attack.genericKill.player=%1$s 在与 %2$s 战斗时被杀死了
|
||||||
death.attack.outsideBorder=%1$s脱离了这个世界
|
death.attack.genericKill.item=%1$s 在与持有 %3$s 的 %2$s 战斗时被杀死了
|
||||||
death.attack.outsideBorder.player=%1$s在与%2$s战斗时脱离了这个世界
|
death.attack.dragonBreath=%1$s 被龙息烤熟了
|
||||||
death.fell.accident.generic=%1$s从高处摔了下来
|
death.attack.dragonBreath.player=%1$s 被 %2$s 的龙息烤熟了
|
||||||
death.fell.assist=%1$s因为%2$s注定要摔死
|
death.attack.dryout=%1$s 因脱水而死
|
||||||
death.fell.assist.item=%1$s因为%2$s使用了%3$s注定要摔死
|
death.attack.dryout.player=%1$s 在试图逃离 %2$s 时因脱水而死
|
||||||
death.fell.finish=%1$s摔伤得太重并被%2$s完结了生命
|
death.attack.outsideBorder=%1$s 脱离了这个世界
|
||||||
death.fell.finish.item=%1$s摔伤得太重并被%2$s用%3$s完结了生命
|
death.attack.outsideBorder.player=%1$s 在与 %2$s 战斗时脱离了这个世界
|
||||||
death.fell.killer=%1$s注定要摔死
|
death.fell.accident.generic=%1$s 从高处摔了下来
|
||||||
|
death.fell.assist=%1$s 因为 %2$s 注定要摔死
|
||||||
|
death.fell.assist.item=%1$s 因为 %2$s 使用了 %3$s 注定要摔死
|
||||||
|
death.fell.finish=%1$s 摔伤得太重并被 %2$s 完结了生命
|
||||||
|
death.fell.finish.player=%1$s 摔伤得太重并被 %2$s 完结了生命
|
||||||
|
death.fell.finish.item=%1$s 摔伤得太重并被 %2$s 用 %3$s 完结了生命
|
||||||
|
death.fell.killer=%1$s 注定要摔死
|
||||||
|
|
||||||
entity.area_effect_cloud.name=区域效果云
|
entity.area_effect_cloud.name=区域效果云
|
||||||
entity.armor_stand.name=盔甲架
|
entity.armor_stand.name=盔甲架
|
||||||
entity.arrow.name=箭
|
entity.arrow.name=箭
|
||||||
@@ -500,6 +513,7 @@ entity.wind_charge_projectile.name=风弹
|
|||||||
entity.breeze_wind_charge_projectile.name=风弹
|
entity.breeze_wind_charge_projectile.name=风弹
|
||||||
entity.breeze.name=旋风人
|
entity.breeze.name=旋风人
|
||||||
entity.creaking.name=嘎枝
|
entity.creaking.name=嘎枝
|
||||||
multiplayer.player.joined=%s加入了游戏
|
multiplayer.player.joined=%s 加入了游戏
|
||||||
multiplayer.player.left=%s退出了游戏
|
multiplayer.player.left=%s 退出了游戏
|
||||||
|
plugin.deathmessages.modapi.warn=可选依赖ModAPI没有被加载,所以客户端侧翻译无法使用,正在启用服务端侧翻译
|
||||||
)";
|
)";
|
||||||
+49
@@ -0,0 +1,49 @@
|
|||||||
|
#include "Entry.h"
|
||||||
|
#include "Global.h"
|
||||||
|
|
||||||
|
#include "ll/api/event/player/PlayerConnectEvent.h"
|
||||||
|
#include "ll/api/event/player/PlayerDieEvent.h"
|
||||||
|
#include "ll/api/event/player/PlayerDisconnectEvent.h"
|
||||||
|
|
||||||
|
#include "ll/api/event/EventBus.h"
|
||||||
|
|
||||||
|
ll::event::ListenerPtr playerConnectEventListener;
|
||||||
|
ll::event::ListenerPtr playerDieEventListener;
|
||||||
|
ll::event::ListenerPtr playerDisconnectEventListener;
|
||||||
|
void ListenEvents() {
|
||||||
|
auto& config = DeathMessages::Entry::getInstance().getConfig();
|
||||||
|
auto& eventBus = ll::event::EventBus::getInstance();
|
||||||
|
if (config.ConsoleLog.JoinMessage) {
|
||||||
|
playerConnectEventListener=eventBus.emplaceListener<ll::event::player::PlayerConnectEvent>([](ll::event::player::PlayerConnectEvent& ev) {
|
||||||
|
infoLogger->info(
|
||||||
|
fmt::format(fg(fmt::color::yellow), fmt::runtime(tr("multiplayer.player.joined", {ev.self().getRealName()})))
|
||||||
|
);
|
||||||
|
|
||||||
|
});
|
||||||
|
}
|
||||||
|
if (config.ConsoleLog.LeftMessage) {
|
||||||
|
playerDisconnectEventListener=eventBus.emplaceListener<ll::event::player::PlayerDisconnectEvent>(
|
||||||
|
[](ll::event::player::PlayerDisconnectEvent& ev) {
|
||||||
|
infoLogger->info(
|
||||||
|
fmt::format(fg(fmt::color::yellow), fmt::runtime(tr("multiplayer.player.left", {ev.self().getRealName()})))
|
||||||
|
);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
if (config.ConsoleLog.DeathMessage) {
|
||||||
|
playerDieEventListener=eventBus.emplaceListener<ll::event::player::PlayerDieEvent>(
|
||||||
|
[](ll::event::player::PlayerDieEvent& ev) {
|
||||||
|
auto [key, params] = ev.source().getDeathMessage(ev.self().getRealName(), &ev.self());
|
||||||
|
auto info = tr(key, params);
|
||||||
|
deathLogger->info(info);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void uninstallEventListeners() {
|
||||||
|
auto& eventBus = ll::event::EventBus::getInstance();
|
||||||
|
eventBus.removeListener(playerDieEventListener);
|
||||||
|
eventBus.removeListener(playerConnectEventListener);
|
||||||
|
eventBus.removeListener(playerDisconnectEventListener);
|
||||||
|
}
|
||||||
+27
-10
@@ -1,26 +1,43 @@
|
|||||||
{
|
{
|
||||||
"format_version": 2,
|
"format_version": 3,
|
||||||
|
"format_uuid": "289f771f-2c9a-4d73-9f3f-8492495a924d",
|
||||||
"tooth": "github.com/GroupMountain/DeathMessages",
|
"tooth": "github.com/GroupMountain/DeathMessages",
|
||||||
"version": "0.13.1",
|
"version": "0.14.0",
|
||||||
"info": {
|
"info": {
|
||||||
"name": "DeathMessages",
|
"name": "DeathMessages",
|
||||||
"description": "Better Death Messages on MCBE",
|
"description": "Better Death Messages on MCBE",
|
||||||
"author": "GroupMountain",
|
"author": "GroupMountain",
|
||||||
|
"source": "github.com/GroupMountain/DeathMessages",
|
||||||
"tags": [
|
"tags": [
|
||||||
"LeviLamina",
|
"platform:levilamina",
|
||||||
"DeathMessages"
|
"type:mod",
|
||||||
|
"DeathMessage",
|
||||||
|
"gmlib"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"asset_url": "https://github.com/GroupMountain/DeathMessages/releases/download/v0.13.1/DeathMessages-windows-x64.zip",
|
|
||||||
"dependencies": {
|
"variants": [
|
||||||
"github.com/GroupMountain/GMLIB": ">=0.13.10"
|
|
||||||
},
|
|
||||||
"files": {
|
|
||||||
"place": [
|
|
||||||
{
|
{
|
||||||
|
"platform": "win-x64",
|
||||||
|
"dependencies": {
|
||||||
|
"github.com/GroupMountain/GMLIB-Release": ">=26.10.0"
|
||||||
|
},
|
||||||
|
"assets": [
|
||||||
|
{
|
||||||
|
"type": "self",
|
||||||
|
"urls": [],
|
||||||
|
"placements": [
|
||||||
|
{
|
||||||
|
"type": "dir",
|
||||||
"src": "DeathMessages/*",
|
"src": "DeathMessages/*",
|
||||||
"dest": "plugins/DeathMessages"
|
"dest": "plugins/DeathMessages"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
],
|
||||||
|
"remove_files": [
|
||||||
|
"plugins/DeathMessages"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
}
|
}
|
||||||
@@ -7,45 +7,21 @@ if not has_config("vs_runtime") then
|
|||||||
set_runtimes("MD")
|
set_runtimes("MD")
|
||||||
end
|
end
|
||||||
|
|
||||||
add_requires("levilamina 1.0.0")
|
add_requires("levilamina 26.10.5",{configs = {target_type = "server"}})
|
||||||
add_requires("levibuildscript 0.3.0")
|
add_requires("levibuildscript")
|
||||||
add_requires("gmlib 0.13.10")
|
add_requires("gmlib 26.10.0")
|
||||||
|
add_requires("modapi 26.10.0")
|
||||||
|
|
||||||
target("DeathMessages") -- Change this to your mod name.
|
target("DeathMessages") -- Change this to your mod name.
|
||||||
add_cxflags(
|
|
||||||
"/EHa",
|
|
||||||
"/utf-8"
|
|
||||||
)
|
|
||||||
add_files(
|
|
||||||
"src/**.cpp"
|
|
||||||
)
|
|
||||||
add_includedirs(
|
|
||||||
"src"
|
|
||||||
)
|
|
||||||
add_packages(
|
|
||||||
"levilamina",
|
|
||||||
"gmlib"
|
|
||||||
)
|
|
||||||
add_defines(
|
|
||||||
"NOMINMAX",
|
|
||||||
"UNICODE",
|
|
||||||
"_HAS_CXX17",
|
|
||||||
"_HAS_CXX20",
|
|
||||||
"_HAS_CXX23"
|
|
||||||
)
|
|
||||||
add_rules("@levibuildscript/linkrule")
|
add_rules("@levibuildscript/linkrule")
|
||||||
set_exceptions("none")
|
add_rules("@levibuildscript/modpacker")
|
||||||
|
add_cxflags( "/EHa", "/utf-8", "/W4", "/w44265", "/w44289", "/w44296", "/w45263", "/w44738", "/w45204")
|
||||||
|
add_defines("NOMINMAX", "UNICODE")
|
||||||
|
add_packages("levilamina","gmlib","modapi")
|
||||||
|
set_exceptions("none") -- To avoid conflicts with /EHa.
|
||||||
set_kind("shared")
|
set_kind("shared")
|
||||||
set_languages("cxx20")
|
set_languages("c++23")
|
||||||
set_symbols("debug")
|
set_symbols("debug")
|
||||||
|
add_headerfiles("src/**.h")
|
||||||
after_build(function (target)
|
add_files("src/**.cpp")
|
||||||
local mod_packer = import("scripts.after_build")
|
add_includedirs("src")
|
||||||
|
|
||||||
local mod_define = {
|
|
||||||
modName = target:name(),
|
|
||||||
modFile = path.filename(target:targetfile()),
|
|
||||||
}
|
|
||||||
|
|
||||||
mod_packer.pack_mod(target,mod_define)
|
|
||||||
end)
|
|
||||||
|
|||||||
Reference in New Issue
Block a user