+1
-2
@@ -1,4 +1,3 @@
|
||||
# Generated from CLion Inspection settings
|
||||
---
|
||||
Checks: '-*,
|
||||
bugprone-argument-comment,
|
||||
@@ -123,7 +122,6 @@ portability-simd-intrinsics,
|
||||
readability-avoid-const-params-in-decls,
|
||||
readability-const-return-type,
|
||||
readability-container-size-empty,
|
||||
readability-convert-member-functions-to-static,
|
||||
readability-delete-null-pointer,
|
||||
readability-deleted-default,
|
||||
readability-inconsistent-declaration-parameter-name,
|
||||
@@ -143,3 +141,4 @@ readability-static-definition-in-anonymous-namespace,
|
||||
readability-string-compare,
|
||||
readability-uniqueptr-delete-release,
|
||||
readability-use-anyofallof'
|
||||
...
|
||||
@@ -7,9 +7,7 @@ Diagnostics:
|
||||
CompileFlags:
|
||||
Add:
|
||||
- "-ferror-limit=0"
|
||||
- "-D__FUNCTION__=\"dummy\""
|
||||
- "-Yumc/_HeaderOutputPredefine.h"
|
||||
- "-FImc/_HeaderOutputPredefine.h" # clangd bug can't find pch file
|
||||
Remove:
|
||||
- "/Yu_HeaderOutputPredefine.h"
|
||||
- "/FI_HeaderOutputPredefine.h"
|
||||
- '-D__FUNCTION__="dummy"'
|
||||
- "-Dnsel_CONFIG_SELECT_EXPECTED=nsel_EXPECTED_NONSTD"
|
||||
- "/std:c++20"
|
||||
- "-D_HAS_CXX23=1"
|
||||
+21
-15
@@ -7,26 +7,32 @@ jobs:
|
||||
build:
|
||||
runs-on: windows-latest
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v2
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Setup XMake
|
||||
uses: xmake-io/github-action-setup-xmake@v1
|
||||
|
||||
- name: Cache
|
||||
uses: actions/cache@v4
|
||||
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
|
||||
with:
|
||||
xmake-version: branch@master
|
||||
- run: |
|
||||
xmake repo -u
|
||||
- name: Update Project
|
||||
run: xmake f -a x64 -m release -p windows -v -y
|
||||
|
||||
- run: |
|
||||
xmake f -a x64 -m release -p windows -v -y
|
||||
- name: Build Project
|
||||
run: xmake -v -y
|
||||
|
||||
- run: |
|
||||
xmake -w -y
|
||||
|
||||
- uses: actions/upload-artifact@v4
|
||||
- name: Upload Artifact
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: ${{ github.event.repository.name }}-windows-x64-${{ github.sha }}
|
||||
path: |
|
||||
|
||||
@@ -7,26 +7,32 @@ jobs:
|
||||
build:
|
||||
runs-on: windows-latest
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v2
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Setup XMake
|
||||
uses: xmake-io/github-action-setup-xmake@v1
|
||||
|
||||
- name: Cache
|
||||
uses: actions/cache@v4
|
||||
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
|
||||
with:
|
||||
xmake-version: branch@master
|
||||
- run: |
|
||||
xmake repo -u
|
||||
- name: Update Project
|
||||
run: xmake f -a x64 -m release -p windows -v -y
|
||||
|
||||
- run: |
|
||||
xmake f -a x64 -m release -p windows -v -y
|
||||
- name: Build Project
|
||||
run: xmake -v -y
|
||||
|
||||
- run: |
|
||||
xmake -w -y
|
||||
|
||||
- uses: actions/upload-artifact@v4
|
||||
- name: Upload Artifact
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: ${{ github.event.repository.name }}-windows-x64-${{ github.sha }}
|
||||
path: |
|
||||
@@ -39,24 +45,26 @@ jobs:
|
||||
contents: write
|
||||
runs-on: ubuntu-latest
|
||||
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:
|
||||
name: ${{ github.event.repository.name }}-windows-x64-${{ github.sha }}
|
||||
path: release/
|
||||
path: artifact
|
||||
|
||||
- run: |
|
||||
cp LICENSE README.md release/
|
||||
|
||||
- name: Archive release
|
||||
- name: Copy Files
|
||||
run: |
|
||||
cd release
|
||||
zip -r ../${{ github.event.repository.name }}-windows-x64.zip *
|
||||
cd ..
|
||||
cp LICENSE README.md artifact/
|
||||
|
||||
- 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:
|
||||
append_body: true
|
||||
files: |
|
||||
${{ github.event.repository.name }}-windows-x64.zip
|
||||
@@ -16,3 +16,4 @@ build/
|
||||
/CMakeLists.txt
|
||||
/bin
|
||||
/.cache
|
||||
/.idea
|
||||
|
||||
@@ -1,6 +1,22 @@
|
||||
# DeathMessages
|
||||
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}",
|
||||
"entry": "${modFile}",
|
||||
"type": "native",
|
||||
"version": "0.13.1",
|
||||
"version": "0.14.0",
|
||||
"author": "GroupMountain",
|
||||
"description": "Better Death Messages",
|
||||
"dependencies": [
|
||||
{
|
||||
"name": "GMLIB"
|
||||
}
|
||||
],
|
||||
"optionalDependencies": [
|
||||
{
|
||||
"name": "ModAPI"
|
||||
}
|
||||
]
|
||||
}
|
||||
+315
-91
@@ -1,143 +1,367 @@
|
||||
#include "Entry.h"
|
||||
#include "GMLIB/Mod/Addons/CustomDamageCause.h"
|
||||
#include "Global.h"
|
||||
#include "ll/api/event/player/PlayerConnectEvent.h"
|
||||
#include "ll/api/event/player/PlayerDisconnectEvent.h"
|
||||
|
||||
#include "ll/api/chrono/GameChrono.h"
|
||||
#include "ll/api/memory/Hook.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() {
|
||||
GMLIB::Mod::DamageCause::DamageCause::setCustomDamageCauseEnabled();
|
||||
GMLIB::Mod::DamageCause::DamageCause::setVanillaCauseMessage(ActorDamageCause::Anvil, "anvil");
|
||||
GMLIB::Mod::DamageCause::DamageCause::setVanillaCauseMessage(ActorDamageCause::EntityAttack, "mob");
|
||||
GMLIB::Mod::DamageCause::DamageCause::setVanillaCauseMessage(ActorDamageCause::RamAttack, "mob");
|
||||
GMLIB::Mod::DamageCause::DamageCause::setVanillaCauseMessage(ActorDamageCause::Drowning, "drown");
|
||||
GMLIB::Mod::DamageCause::DamageCause::setVanillaCauseMessage(ActorDamageCause::FallingBlock, "fallingBlock");
|
||||
GMLIB::Mod::DamageCause::DamageCause::setVanillaCauseMessage(ActorDamageCause::Fire, "inFire");
|
||||
GMLIB::Mod::DamageCause::DamageCause::setVanillaCauseMessage(ActorDamageCause::FireTick, "onFire");
|
||||
GMLIB::Mod::DamageCause::DamageCause::setVanillaCauseMessage(ActorDamageCause::Fireworks, "fireworks");
|
||||
GMLIB::Mod::DamageCause::DamageCause::setVanillaCauseMessage(ActorDamageCause::FlyIntoWall, "flyIntoWall");
|
||||
GMLIB::Mod::DamageCause::DamageCause::setVanillaCauseMessage(ActorDamageCause::Freezing, "freeze");
|
||||
GMLIB::Mod::DamageCause::DamageCause::setVanillaCauseMessage(ActorDamageCause::Lava, "lava");
|
||||
GMLIB::Mod::DamageCause::DamageCause::setVanillaCauseMessage(ActorDamageCause::Lightning, "lightningBolt");
|
||||
GMLIB::Mod::DamageCause::DamageCause::setVanillaCauseMessage(ActorDamageCause::Wither, "wither");
|
||||
GMLIB::Mod::DamageCause::DamageCause::setVanillaCauseMessage(ActorDamageCause::Magic, "indirectMagic");
|
||||
GMLIB::Mod::DamageCause::DamageCause::setVanillaCauseMessage(ActorDamageCause::Magma, "hotFloor");
|
||||
GMLIB::Mod::DamageCause::DamageCause::setVanillaCauseMessage(ActorDamageCause::Stalactite, "stalactite");
|
||||
GMLIB::Mod::DamageCause::DamageCause::setVanillaCauseMessage(ActorDamageCause::Stalagmite, "stalagmite");
|
||||
GMLIB::Mod::DamageCause::DamageCause::setVanillaCauseMessage(ActorDamageCause::Starve, "starve");
|
||||
GMLIB::Mod::DamageCause::DamageCause::setVanillaCauseMessage(ActorDamageCause::Suffocation, "inWall");
|
||||
GMLIB::Mod::DamageCause::DamageCause::setVanillaCauseMessage(ActorDamageCause::SonicBoom, "sonicBoom");
|
||||
GMLIB::Mod::DamageCause::DamageCause::setVanillaCauseMessage(ActorDamageCause::Void, "outOfWorld");
|
||||
GMLIB::Mod::DamageCause::DamageCause::setVanillaCauseMessage(ActorDamageCause::SelfDestruct, "genericKill");
|
||||
GMLIB::Mod::DamageCause::DamageCause::setVanillaCauseMessage(ActorDamageCause::Projectile, "thrown");
|
||||
GMLIB::Mod::DamageCause::DamageCause::setVanillaCauseMessage(ActorDamageCause::Thorns, "thorns");
|
||||
GMLIB::Mod::DamageCause::DamageCause::registerCustomDeathMessage(
|
||||
ActorDamageCause::Projectile,
|
||||
setVanillaCauseMessage(SharedTypes::Legacy::ActorDamageCause::Anvil, "anvil");
|
||||
setVanillaCauseMessage(SharedTypes::Legacy::ActorDamageCause::EntityAttack, "mob");
|
||||
setVanillaCauseMessage(SharedTypes::Legacy::ActorDamageCause::RamAttack, "mob");
|
||||
setVanillaCauseMessage(SharedTypes::Legacy::ActorDamageCause::Drowning, "drown");
|
||||
setVanillaCauseMessage(SharedTypes::Legacy::ActorDamageCause::FallingBlock, "fallingBlock");
|
||||
setVanillaCauseMessage(SharedTypes::Legacy::ActorDamageCause::Fire, "inFire");
|
||||
setVanillaCauseMessage(SharedTypes::Legacy::ActorDamageCause::FireTick, "onFire");
|
||||
setVanillaCauseMessage(SharedTypes::Legacy::ActorDamageCause::Fireworks, "fireworks");
|
||||
setVanillaCauseMessage(SharedTypes::Legacy::ActorDamageCause::FlyIntoWall, "flyIntoWall");
|
||||
setVanillaCauseMessage(SharedTypes::Legacy::ActorDamageCause::Freezing, "freeze");
|
||||
setVanillaCauseMessage(SharedTypes::Legacy::ActorDamageCause::Lava, "lava");
|
||||
setVanillaCauseMessage(SharedTypes::Legacy::ActorDamageCause::Lightning, "lightningBolt");
|
||||
setVanillaCauseMessage(SharedTypes::Legacy::ActorDamageCause::Wither, "wither");
|
||||
setVanillaCauseMessage(SharedTypes::Legacy::ActorDamageCause::Magic, "indirectMagic");
|
||||
setVanillaCauseMessage(SharedTypes::Legacy::ActorDamageCause::Magma, "hotFloor");
|
||||
setVanillaCauseMessage(SharedTypes::Legacy::ActorDamageCause::Stalactite, "stalactite");
|
||||
setVanillaCauseMessage(SharedTypes::Legacy::ActorDamageCause::Stalagmite, "stalagmite");
|
||||
setVanillaCauseMessage(SharedTypes::Legacy::ActorDamageCause::Starve, "starve");
|
||||
setVanillaCauseMessage(SharedTypes::Legacy::ActorDamageCause::Suffocation, "inWall");
|
||||
setVanillaCauseMessage(SharedTypes::Legacy::ActorDamageCause::SonicBoom, "sonicBoom");
|
||||
setVanillaCauseMessage(SharedTypes::Legacy::ActorDamageCause::Void, "outOfWorld");
|
||||
setVanillaCauseMessage(SharedTypes::Legacy::ActorDamageCause::SelfDestruct, "genericKill");
|
||||
setVanillaCauseMessage(SharedTypes::Legacy::ActorDamageCause::Projectile, "thrown");
|
||||
setVanillaCauseMessage(SharedTypes::Legacy::ActorDamageCause::Thorns, "thorns");
|
||||
registerCustomDeathMessage(
|
||||
SharedTypes::Legacy::ActorDamageCause::Projectile,
|
||||
"death.attack.fireball.item",
|
||||
"minecraft:small_fireball"
|
||||
);
|
||||
GMLIB::Mod::DamageCause::DamageCause::registerCustomDeathMessage(
|
||||
ActorDamageCause::Projectile,
|
||||
registerCustomDeathMessage(
|
||||
SharedTypes::Legacy::ActorDamageCause::Projectile,
|
||||
"death.attack.trident.item",
|
||||
"minecraft:thrown_trident"
|
||||
);
|
||||
GMLIB::Mod::DamageCause::DamageCause::registerCustomDeathMessage(
|
||||
ActorDamageCause::Projectile,
|
||||
registerCustomDeathMessage(
|
||||
SharedTypes::Legacy::ActorDamageCause::Projectile,
|
||||
"death.attack.spit",
|
||||
"minecraft:llama_spit"
|
||||
);
|
||||
GMLIB::Mod::DamageCause::DamageCause::registerCustomDeathMessage(
|
||||
ActorDamageCause::Projectile,
|
||||
registerCustomDeathMessage(
|
||||
SharedTypes::Legacy::ActorDamageCause::Projectile,
|
||||
"death.attack.bullet",
|
||||
"minecraft:shulker_bullet"
|
||||
);
|
||||
GMLIB::Mod::DamageCause::DamageCause::registerCustomDeathMessage(
|
||||
ActorDamageCause::Projectile,
|
||||
registerCustomDeathMessage(
|
||||
SharedTypes::Legacy::ActorDamageCause::Projectile,
|
||||
"death.attack.arrow.item",
|
||||
"minecraft:arrow"
|
||||
);
|
||||
GMLIB::Mod::DamageCause::DamageCause::registerCustomDeathMessage(
|
||||
ActorDamageCause::Projectile,
|
||||
registerCustomDeathMessage(
|
||||
SharedTypes::Legacy::ActorDamageCause::Projectile,
|
||||
"death.attack.explosion.player",
|
||||
"minecraft:fireball"
|
||||
);
|
||||
GMLIB::Mod::DamageCause::DamageCause::registerCustomDeathMessage(
|
||||
ActorDamageCause::Projectile,
|
||||
registerCustomDeathMessage(
|
||||
SharedTypes::Legacy::ActorDamageCause::Projectile,
|
||||
"death.attack.mob",
|
||||
"minecraft:breeze_wind_charge_projectile"
|
||||
);
|
||||
GMLIB::Mod::DamageCause::DamageCause::registerCustomDeathMessage(
|
||||
ActorDamageCause::Magic,
|
||||
registerCustomDeathMessage(
|
||||
SharedTypes::Legacy::ActorDamageCause::Magic,
|
||||
"death.attack.magic",
|
||||
"empty"
|
||||
);
|
||||
GMLIB::Mod::DamageCause::DamageCause::registerCustomDeathMessage(
|
||||
ActorDamageCause::SonicBoom,
|
||||
registerCustomDeathMessage(
|
||||
SharedTypes::Legacy::ActorDamageCause::SonicBoom,
|
||||
"death.attack.sonicBoom",
|
||||
"minecraft:warden"
|
||||
);
|
||||
GMLIB::Mod::DamageCause::DamageCause::registerCustomDeathMessage(
|
||||
ActorDamageCause::Thorns,
|
||||
registerCustomDeathMessage(
|
||||
SharedTypes::Legacy::ActorDamageCause::Thorns,
|
||||
"death.attack.generic",
|
||||
"empty"
|
||||
);
|
||||
GMLIB::Mod::DamageCause::DamageCause::registerCustomDeathMessage(
|
||||
ActorDamageCause::EntityExplosion,
|
||||
registerCustomDeathMessage(
|
||||
SharedTypes::Legacy::ActorDamageCause::EntityExplosion,
|
||||
"death.attack.explosion.player",
|
||||
"all"
|
||||
);
|
||||
GMLIB::Mod::DamageCause::DamageCause::registerCustomDeathMessage(
|
||||
ActorDamageCause::EntityExplosion,
|
||||
registerCustomDeathMessage(
|
||||
SharedTypes::Legacy::ActorDamageCause::EntityExplosion,
|
||||
"minecraft:wither_skull",
|
||||
"death.attack.witherSkull.item"
|
||||
);
|
||||
GMLIB::Mod::DamageCause::DamageCause::registerCustomDeathMessage(
|
||||
ActorDamageCause::EntityExplosion,
|
||||
registerCustomDeathMessage(
|
||||
SharedTypes::Legacy::ActorDamageCause::EntityExplosion,
|
||||
"minecraft:wither_skull_dangerous",
|
||||
"death.attack.witherSkull.item"
|
||||
);
|
||||
GMLIB::Mod::DamageCause::DamageCause::registerCustomDeathMessage(
|
||||
ActorDamageCause::EntityAttack,
|
||||
registerCustomDeathMessage(
|
||||
SharedTypes::Legacy::ActorDamageCause::EntityAttack,
|
||||
"minecraft:player",
|
||||
"death.attack.player.item"
|
||||
);
|
||||
GMLIB::Mod::DamageCause::DamageCause::registerCustomDeathMessage(
|
||||
ActorDamageCause::EntityAttack,
|
||||
registerCustomDeathMessage(
|
||||
SharedTypes::Legacy::ActorDamageCause::EntityAttack,
|
||||
"minecraft:bee",
|
||||
"death.attack.sting.item"
|
||||
);
|
||||
GMLIB::Mod::DamageCause::DamageCause::registerCustomDeathMessage(
|
||||
ActorDamageCause::RamAttack,
|
||||
registerCustomDeathMessage(
|
||||
SharedTypes::Legacy::ActorDamageCause::RamAttack,
|
||||
"minecraft:player",
|
||||
"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 "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();
|
||||
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> infoLogger = loggerRegistry.getOrCreate("Server");
|
||||
|
||||
extern void uninstallHooks();
|
||||
extern void RegisterDamageDefinition();
|
||||
extern void uninstallEventListeners();
|
||||
extern void ListenEvents();
|
||||
|
||||
namespace DeathMessages {
|
||||
|
||||
@@ -16,25 +33,30 @@ Entry& Entry::getInstance() {
|
||||
}
|
||||
|
||||
bool Entry::load() {
|
||||
isResourceI18nLoaded=false;
|
||||
|
||||
mConfig.emplace();
|
||||
if (!ll::config::loadConfig(*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) {
|
||||
auto& path = getConfig().FileLog.Path;
|
||||
ll::Polymorphic<ll::io::PatternFormatter> polymorphicFormatter =
|
||||
ll::makePolymorphic<ll::io::PatternFormatter>("[{3:.3%F %T.} {2}][{1}] {0}", false);
|
||||
deathLogger->addSink(std::make_shared<ll::io::FileSink>(path, polymorphicFormatter));
|
||||
}
|
||||
loadI18n();
|
||||
if ((!getConfig().ServerSideTranslation.Enabled)&&ll::mod::ModManagerRegistry::getInstance().hasMod("ModAPI")) {
|
||||
loadResourcePack();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Entry::enable() {
|
||||
if (!ll::mod::ModManagerRegistry::getInstance().hasMod("ModAPI")) {
|
||||
getSelf().getLogger().warn(tr("plugin.deathmessages.modapi.warn"));
|
||||
}
|
||||
RegisterDamageDefinition();
|
||||
ListenEvents();
|
||||
return true;
|
||||
@@ -45,36 +67,51 @@ bool Entry::disable() { return true; }
|
||||
bool Entry::unload() {
|
||||
mConfig.reset();
|
||||
mI18n.reset();
|
||||
uninstallHooks();
|
||||
loggerRegistry.erase(MOD_NAME);
|
||||
loggerRegistry.erase("Death");
|
||||
loggerRegistry.erase("Server");
|
||||
// getInstance().reset();
|
||||
return true;
|
||||
}
|
||||
|
||||
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() {
|
||||
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("zh_CN", zh_CN);
|
||||
mI18n->loadAllLanguages();
|
||||
mI18n->setDefaultLanguage("zh_CN");
|
||||
}
|
||||
|
||||
|
||||
|
||||
void Entry::loadResourcePack() {
|
||||
GMLIB::Mod::VanillaFix::setFixI18nEnabled();
|
||||
auto resource = GMLIB::Files::ResourceLanguage(getSelf().getModDir() / u8"resource", MOD_NAME, 0, 8, 0);
|
||||
resource.addLanguage("en_US", en_US);
|
||||
resource.addLanguage("zh_CN", zh_CN);
|
||||
auto mResource = std::make_unique<gmlib::i18n::ResourceI18n>(getSelf().getModDir() / u8"lang", MOD_NAME, 0, 16, 1);
|
||||
mResource->addLanguage("en_US", en_US);
|
||||
mResource->addLanguage("zh_CN", zh_CN);
|
||||
mResource->loadAllLanguages();
|
||||
isResourceI18nLoaded=true;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
} // namespace DeathMessages
|
||||
|
||||
LL_REGISTER_MOD(DeathMessages::Entry, DeathMessages::Entry::getInstance());
|
||||
|
||||
std::string tr(std::string const& key, std::vector<std::string> const& params) {
|
||||
if (auto i18n = DeathMessages::Entry::getInstance().getI18n()) {
|
||||
return i18n->get(key, params);
|
||||
}
|
||||
return ::I18nAPI::get(key, params);
|
||||
auto& i18n = DeathMessages::Entry::getInstance().getI18n();
|
||||
return i18n.get(key, params);
|
||||
|
||||
|
||||
return key;
|
||||
}
|
||||
|
||||
|
||||
+9
-2
@@ -2,6 +2,11 @@
|
||||
#include "Config.h"
|
||||
#include "Global.h"
|
||||
|
||||
#include "ll/api/mod/Mod.h"
|
||||
#include <ll/api/mod/NativeMod.h>
|
||||
|
||||
#include <gmlib/gm/i18n/LangI18n.h>
|
||||
|
||||
namespace DeathMessages {
|
||||
|
||||
class Entry {
|
||||
@@ -27,16 +32,18 @@ public:
|
||||
|
||||
Config& getConfig();
|
||||
|
||||
std::optional<GMLIB::Files::I18n::LangI18n> getI18n();
|
||||
gmlib::i18n::LangI18n& getI18n();
|
||||
|
||||
void loadI18n();
|
||||
|
||||
void loadResourcePack();
|
||||
|
||||
|
||||
bool isResourceI18nLoaded;
|
||||
private:
|
||||
ll::mod::NativeMod& mSelf;
|
||||
std::optional<Config> mConfig;
|
||||
std::optional<GMLIB::Files::I18n::LangI18n> mI18n;
|
||||
std::unique_ptr<gmlib::i18n::LangI18n> mI18n;
|
||||
};
|
||||
|
||||
} // namespace DeathMessages
|
||||
|
||||
+11
-4
@@ -1,13 +1,20 @@
|
||||
#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"
|
||||
|
||||
extern std::shared_ptr<ll::io::Logger> logger;
|
||||
extern std::shared_ptr<ll::io::Logger> deathLogger;
|
||||
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 void ListenEvents();
|
||||
extern DeathMessageResult translateDeathMessage(DeathMessageResult origin, std::string name, Actor* dead, ActorDamageSource* ads);
|
||||
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();
|
||||
}
|
||||
+17
-3
@@ -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.player=%1$s died from %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.inFire=%1$s was consumed by fire
|
||||
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.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.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.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.trident=%1$s was impaled by %2$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.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.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.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
|
||||
@@ -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.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.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.killer=%1$s was doomed to fall
|
||||
entity.area_effect_cloud.name=Area Effect Cloud
|
||||
@@ -250,11 +255,12 @@ entity.breeze.name=Breeze
|
||||
entity.creaking.name=Creaking
|
||||
multiplayer.player.joined=%s joined 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"(
|
||||
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.arrow=%1$s被 %2$s 射杀
|
||||
death.attack.arrow.item=%1$s 被 %2$s 用 %3$s 射杀
|
||||
@@ -273,7 +279,7 @@ death.attack.fall=%1$s落地过猛
|
||||
death.attack.fall.player=%1$s 在试图逃离 %2$s 时落地过猛
|
||||
death.attack.fall.item=%1$s 在试图逃离持有 %3$s 的 %2$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.fireball=%1$s被 %2$s 用火球烧死了
|
||||
death.attack.fireball.item=%1$s被 %2$s 用 %3$s 发射的火球烧死了
|
||||
@@ -286,6 +292,7 @@ death.attack.flyIntoWall.item=%1$s在试图逃离持有%3$s的%2$s时感受到
|
||||
death.attack.generic=%1$s 死了
|
||||
death.attack.generic.player=%1$s 死于 %2$s
|
||||
death.attack.indirectMagic=%1$s 被 %2$s 使用的魔法杀死了
|
||||
death.attack.indirectMagic.player=%1$s 被 %2$s 使用的魔法杀死了
|
||||
death.attack.indirectMagic.item=%1$s 被 %2$s 用 %3$s 杀死了
|
||||
death.attack.inFire=%1$s 浴火焚身
|
||||
death.attack.inFire.player=%1$s 在与 %2$s 战斗时不慎走入了火中
|
||||
@@ -304,6 +311,7 @@ death.attack.hotFloor=%1$s发现地板是熔岩做的
|
||||
death.attack.hotFloor.player=%1$s 因 %2$s 而步入危险之地
|
||||
death.attack.hotFloor.item=%1$s 因持有 %3$s 的 %2$s 而步入危险之地
|
||||
death.attack.mob=%1$s 被 %2$s 杀死了
|
||||
death.attack.mob.player=%1$s 被 %2$s 杀死了
|
||||
death.attack.mob.item=%1$s 被 %2$s 用 %3$s 杀死了
|
||||
death.attack.sting=%1$s 被 %2$s 蛰死了
|
||||
death.attack.sting.item=%1$s 被 %2$s 用 %3$s 蛰死了
|
||||
@@ -322,9 +330,11 @@ death.attack.starve.item=%1$s在与持有%3$s的%2$s战斗时饿死了
|
||||
death.attack.sweetBerry=%1$s 被甜浆果丛刺死了
|
||||
death.attack.sweetBerry.player=%1$s 在试图逃离 %2$s 时被甜浆果丛刺死了
|
||||
death.attack.sweetBerry.item=%1$s 在试图逃离持有 %3$s 的 %2$s 时被甜浆果丛刺死了
|
||||
death.attack.thorns=%1$s在试图伤害%2$s时被杀
|
||||
death.attack.thorns=%1$s 在试图伤害 %2$s
|
||||
death.attack.thorns.player=%1$s 在试图伤害 %2$s 时被杀
|
||||
death.attack.thorns.item=%1$s 在试图伤害 %2$s 时被 %3$s 杀死
|
||||
death.attack.thrown=%1$s 被 %2$s 给砸死了
|
||||
death.attack.thrown.player=%1$s 被 %2$s 给砸死了
|
||||
death.attack.thrown.item=%1$s 被 %2$s 用 %3$s 给砸死了
|
||||
death.attack.trident=%1$s 被 %2$s 刺穿了
|
||||
death.attack.trident.item=%1$s 被 %2$s 使用 %3$s 刺穿了
|
||||
@@ -336,6 +346,7 @@ death.attack.freeze.player=%1$s被%2$s冻死了
|
||||
death.attack.freeze.item=%1$s 被持有 %3$s 的 %2$s 冻死了
|
||||
death.attack.sonicBoom=%1$s 被一道音波尖啸抹除了
|
||||
death.attack.sonicBoom.player=%1$s 在试图逃离 %2$s 时被一道音波尖啸抹除了
|
||||
death.attack.sonicBoom.item=%1$s 在试图逃离 %2$s 时被一道音波尖啸抹除了
|
||||
death.attack.stalactite=%1$s 被坠落的钟乳石刺穿了
|
||||
death.attack.stalactite.player=%1$s 在与 %2$s 战斗时被坠落的钟乳石刺穿了
|
||||
death.attack.stalactite.item=%1$s 在与持有 %3$s 的 %2$s 战斗时被坠落的钟乳石刺穿了
|
||||
@@ -358,8 +369,10 @@ 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.armor_stand.name=盔甲架
|
||||
entity.arrow.name=箭
|
||||
@@ -502,4 +515,5 @@ entity.breeze.name=旋风人
|
||||
entity.creaking.name=嘎枝
|
||||
multiplayer.player.joined=%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",
|
||||
"version": "0.13.1",
|
||||
"version": "0.14.0",
|
||||
"info": {
|
||||
"name": "DeathMessages",
|
||||
"description": "Better Death Messages on MCBE",
|
||||
"author": "GroupMountain",
|
||||
"source": "github.com/GroupMountain/DeathMessages",
|
||||
"tags": [
|
||||
"LeviLamina",
|
||||
"DeathMessages"
|
||||
"platform:levilamina",
|
||||
"type:mod",
|
||||
"DeathMessage",
|
||||
"gmlib"
|
||||
]
|
||||
},
|
||||
"asset_url": "https://github.com/GroupMountain/DeathMessages/releases/download/v0.13.1/DeathMessages-windows-x64.zip",
|
||||
"dependencies": {
|
||||
"github.com/GroupMountain/GMLIB": ">=0.13.10"
|
||||
},
|
||||
"files": {
|
||||
"place": [
|
||||
|
||||
"variants": [
|
||||
{
|
||||
"platform": "win-x64",
|
||||
"dependencies": {
|
||||
"github.com/GroupMountain/GMLIB-Release": ">=26.10.0"
|
||||
},
|
||||
"assets": [
|
||||
{
|
||||
"type": "self",
|
||||
"urls": [],
|
||||
"placements": [
|
||||
{
|
||||
"type": "dir",
|
||||
"src": "DeathMessages/*",
|
||||
"dest": "plugins/DeathMessages"
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"remove_files": [
|
||||
"plugins/DeathMessages"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -7,45 +7,21 @@ if not has_config("vs_runtime") then
|
||||
set_runtimes("MD")
|
||||
end
|
||||
|
||||
add_requires("levilamina 1.0.0")
|
||||
add_requires("levibuildscript 0.3.0")
|
||||
add_requires("gmlib 0.13.10")
|
||||
add_requires("levilamina 26.10.5",{configs = {target_type = "server"}})
|
||||
add_requires("levibuildscript")
|
||||
add_requires("gmlib 26.10.0")
|
||||
add_requires("modapi 26.10.0")
|
||||
|
||||
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")
|
||||
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_languages("cxx20")
|
||||
set_languages("c++23")
|
||||
set_symbols("debug")
|
||||
|
||||
after_build(function (target)
|
||||
local mod_packer = import("scripts.after_build")
|
||||
|
||||
local mod_define = {
|
||||
modName = target:name(),
|
||||
modFile = path.filename(target:targetfile()),
|
||||
}
|
||||
|
||||
mod_packer.pack_mod(target,mod_define)
|
||||
end)
|
||||
add_headerfiles("src/**.h")
|
||||
add_files("src/**.cpp")
|
||||
add_includedirs("src")
|
||||
|
||||
Reference in New Issue
Block a user