feat: adapt to Levilamina 26.10.5

Code references logic from ActorDamageCause.cc(GMLIB 0.13.5)
This commit is contained in:
2026-06-20 16:49:21 +08:00
Unverified
parent a525d066c6
commit ce09c29431
6 changed files with 539 additions and 115 deletions
+1
View File
@@ -16,3 +16,4 @@ build/
/CMakeLists.txt /CMakeLists.txt
/bin /bin
/.cache /.cache
/.idea
+493 -63
View File
@@ -1,123 +1,553 @@
#include "Entry.h" #include "Entry.h"
#include "GMLIB/Mod/Addons/CustomDamageCause.h"
#include "Global.h"
#include "ll/api/event/player/PlayerConnectEvent.h" #include "ll/api/event/player/PlayerConnectEvent.h"
#include "ll/api/event/player/PlayerDisconnectEvent.h" #include "ll/api/event/player/PlayerDisconnectEvent.h"
#include "ll/api/memory/Hook.h"
#include "ll/api/chrono/GameChrono.h"
#include "ll/api/thread/ThreadPoolExecutor.h"
#include <chrono>
#include "mc/world/actor/Mob.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 "ll/api/service/Bedrock.h"
#include "mc/world/level/Level.h"
#include "mc/world/actor/Actor.h"
phmap::flat_hash_map<int64, float> mFallHeightMap;
phmap::flat_hash_map<int64, ActorUniqueID> mHurtByEntityMap;
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();
logger->info("跌落高度为 {}", getFallDistance());
}
if (hasCategory(ActorCategory::Player) || isTame()) {
if (mLastHurtByMobTime != 0) {
auto hm = getLastHurtByMob();
mHurtByEntityMap[uid.rawID] = hm->getOrCreateUniqueID();
if (!getLastHurtByMob()->getNameTag().empty()) logger->info("伤害来源为 {}", getLastHurtByMob()->getNameTag());
logger->info("伤害来源为 {}", getLastHurtByMob()->getTypeName());
if (!getLastHurtByMob()->getCarriedItem().getCustomName().empty()) logger->info("伤害来源为 {}", getLastHurtByMob()->getCarriedItem().getCustomName());
}
}
origin(ads);
auto& executor = ll::thread::ThreadPoolExecutor::getDefault();
auto callback = executor.executeAfter(
[] {
mHurtByEntityMap.clear();
mFallHeightMap.clear();
},
ll::chrono::game::ticks(1)
);
}
using DeathMessageResult = std::pair<std::string, std::vector<std::string>>;
int mMaxCauseId = 34;
std::vector<std::pair<std::string, int>> mCustomCauseMap;
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;
bool isCustomDefinition(int cause) {
if (cause >= 35) {
return true;
}
if (mVanillaCauseMessage.count(cause)) {
return true;
}
return false;
}
bool isCustomCauseExist(std::string const& causeName) {
for (auto& key : mCustomCauseMap) {
if (key.first == causeName) {
return true;
}
}
return false;
}
bool isCustomCauseExist(int cause) {
for (auto& key : mCustomCauseMap) {
if (key.second == cause) {
return true;
}
}
return false;
}
SharedTypes::Legacy::ActorDamageCause getCustomCause(std::string const& causeName) {
for (auto& key : mCustomCauseMap) {
if (key.first == causeName) {
return (SharedTypes::Legacy::ActorDamageCause)key.second;
}
}
return SharedTypes::Legacy::ActorDamageCause::None;
}
std::string getCustomCause(SharedTypes::Legacy::ActorDamageCause cause) {
for (auto& key : mCustomCauseMap) {
if ((SharedTypes::Legacy::ActorDamageCause)key.second == cause) {
return key.first;
}
}
return "none";
}
std::string getCause(SharedTypes::Legacy::ActorDamageCause cause) {
auto id = (int)cause;
if (isCustomCauseExist(id)) {
return getCustomCause(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 (isCustomDefinition(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 = "[" + 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", "");
}
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, isEscaping, 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 (killer == nullptr && mHurtByEntityMap.count(uid)) {
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);
}
LL_AUTO_TYPE_INSTANCE_HOOK(
DeathMessageHook1,
HookPriority::Lowest,
ActorDamageSource,
&ActorDamageSource::$getDeathMessage,
DeathMessageResult,
std::string a1,
Actor* a2
) {
auto originl = origin(a1, a2);
logger->info("原消息name为 {}", a1);
logger->info("原消息为 {}", originl.first);
auto res = translateDeathMessage(originl, a1, a2, this);
return res;
}
LL_AUTO_TYPE_INSTANCE_HOOK(
DeathMessageHook2,
HookPriority::Lowest,
ActorDamageByActorSource,
&ActorDamageByActorSource::$getDeathMessage,
DeathMessageResult,
std::string a1,
Actor* a2
) {
auto originl = origin(a1, a2);
logger->info("原消息name为 {}", a1);
logger->info("原消息为 {}", originl.first);
auto res = translateDeathMessage(originl, a1, a2, this);
return res;
}
LL_AUTO_TYPE_INSTANCE_HOOK(
DeathMessageHook3,
HookPriority::Lowest,
ActorDamageByBlockSource,
&ActorDamageByBlockSource::$getDeathMessage,
DeathMessageResult,
std::string a1,
Actor* a2
) {
auto originl = origin(a1, a2);
logger->info("原消息name为 {}", a1);
logger->info("原消息为 {}", originl.first);
auto res = translateDeathMessage(originl, a1, a2, this);
return res;
}
LL_AUTO_TYPE_INSTANCE_HOOK(
DeathMessageHook4,
HookPriority::Lowest,
ActorDamageByChildActorSource,
&ActorDamageByChildActorSource::$getDeathMessage,
DeathMessageResult,
std::string a1,
Actor* a2
) {
auto originl = origin(a1, a2);
logger->info("原消息name为 {}", a1);
logger->info("原消息为 {}", originl.first);
auto res = translateDeathMessage(originl, a1, a2, this);
return res;
}
int getNextCauseId() {
mMaxCauseId++;
return mMaxCauseId;
}
bool registerDamageCause(std::string const& causeName) {
if (!isCustomCauseExist(causeName)) {
auto id = getNextCauseId();
mCustomCauseMap.push_back({causeName, id});
return true;
}
return false;
}
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;
}
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() { void ListenEvents() {
auto& config = DeathMessages::Entry::getInstance().getConfig(); auto& config = DeathMessages::Entry::getInstance().getConfig();
auto& eventBus = ll::event::EventBus::getInstance(); auto& eventBus = ll::event::EventBus::getInstance();
if (config.ConsoleLog.JoinMessage) { if (config.ConsoleLog.JoinMessage) {
eventBus.emplaceListener<ll::event::player::PlayerConnectEvent>([](ll::event::player::PlayerConnectEvent& ev) { 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()})) infoLogger->info(fmt::format(fg(fmt::color::yellow), tr("multiplayer.player.joined", {ev.self().getRealName()}))
); );
}); });
} }
@@ -125,7 +555,7 @@ void ListenEvents() {
eventBus.emplaceListener<ll::event::player::PlayerDisconnectEvent>( eventBus.emplaceListener<ll::event::player::PlayerDisconnectEvent>(
[](ll::event::player::PlayerDisconnectEvent& ev) { [](ll::event::player::PlayerDisconnectEvent& ev) {
infoLogger->info( infoLogger->info(
fmt::format(fg(fmt::color::yellow), tr("multiplayer.player.left", {ev.self().getName()})) fmt::format(fg(fmt::color::yellow), tr("multiplayer.player.left", {ev.self().getRealName()}))
); );
} }
); );
@@ -140,4 +570,4 @@ void ListenEvents() {
} }
); );
} }
} }*/
+22 -9
View File
@@ -1,6 +1,16 @@
#include "Entry.h" #include "Entry.h"
#include "Global.h" #include "Global.h"
#include "Language.h" #include "Language.h"
#include "ll/api/mod/Mod.h"
#include "ll/api/Config.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/RegisterHelper.h"
#include "ll/api/data/IndirectValue.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);
@@ -35,8 +45,8 @@ bool Entry::load() {
} }
bool Entry::enable() { bool Entry::enable() {
RegisterDamageDefinition(); /* RegisterDamageDefinition();
ListenEvents(); ListenEvents();*/
return true; return true;
} }
@@ -51,10 +61,10 @@ bool Entry::unload() {
Config& Entry::getConfig() { return mConfig.value(); } Config& Entry::getConfig() { return mConfig.value(); }
std::optional<GMLIB::Files::I18n::LangI18n> Entry::getI18n() { return mI18n; } std::unique_ptr<gmlib::i18n::LangI18n> Entry::getI18n() { return std::move(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();
@@ -62,8 +72,7 @@ void Entry::loadI18n() {
} }
void Entry::loadResourcePack() { void Entry::loadResourcePack() {
GMLIB::Mod::VanillaFix::setFixI18nEnabled(); auto resource = gmlib::i18n::ResourceI18n(getSelf().getModDir() / u8"resource", MOD_NAME, 0, 8, 0);
auto resource = GMLIB::Files::ResourceLanguage(getSelf().getModDir() / u8"resource", MOD_NAME, 0, 8, 0);
resource.addLanguage("en_US", en_US); resource.addLanguage("en_US", en_US);
resource.addLanguage("zh_CN", zh_CN); resource.addLanguage("zh_CN", zh_CN);
} }
@@ -72,9 +81,13 @@ void Entry::loadResourcePack() {
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()) { if (auto i18n = DeathMessages::Entry::getInstance().getI18n()) {
return i18n->get(key, params); return i18n->get(key, params);
} }
return ::I18nAPI::get(key, params); auto i18n = DeathMessages::Entry::getI18n();
}
return i18n->get(key, params);
}*/
+7 -2
View File
@@ -1,6 +1,11 @@
#pragma once #pragma once
#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 {
@@ -27,7 +32,7 @@ public:
Config& getConfig(); Config& getConfig();
std::optional<GMLIB::Files::I18n::LangI18n> getI18n(); std::unique_ptr<gmlib::i18n::LangI18n> getI18n();
void loadI18n(); void loadI18n();
@@ -36,7 +41,7 @@ public:
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
+3 -3
View File
@@ -1,5 +1,5 @@
#pragma once #pragma once
#include <include_all.h> #include <ll/api/io/Logger.h>
#define MOD_NAME "DeathMessages" #define MOD_NAME "DeathMessages"
@@ -7,7 +7,7 @@ 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 std::string tr(std::string const& key, std::vector<std::string> const& data = {}); /*extern std::string tr(std::string const& key, std::vector<std::string> const& data = {});
extern void RegisterDamageDefinition(); extern void RegisterDamageDefinition();
extern void ListenEvents(); extern void ListenEvents();*/
+12 -37
View File
@@ -7,45 +7,20 @@ 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")
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")
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)