合并本地领先源码:旧UI、GM疲劳燃烧、白金徽章孔、宠物修复、支援兵普攻开关
This commit is contained in:
1 parent
f2debaf9bf
commit
70b3c5a6dc
57 files changed
+4256
-30
No files matched your search
@@ -0,0 +1,434 @@
|
||||
package dnfbridge
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
dnfauction "longheng.io/server/internal/modules/dnf/auction"
|
||||
)
|
||||
|
||||
type currentServerFeatureSettings struct {
|
||||
RaidReviveSeconds int `json:"raidReviveSeconds"`
|
||||
AllDeadReturnSeconds int `json:"allDeadReturnSeconds"`
|
||||
AllowFreeRevive *bool `json:"allowFreeRevive"`
|
||||
HellOrbChance int `json:"hellOrbChance"`
|
||||
HellDropChanceDenominator int `json:"hellDropChanceDenominator"`
|
||||
EquipmentRollMultiplier int `json:"equipmentRollMultiplier"`
|
||||
EpicPieceRollMultiplier int `json:"epicPieceRollMultiplier"`
|
||||
AntonRaidAttackSeconds int `json:"antonRaidAttackSeconds"`
|
||||
LukeEnergyRecoveryPercent int `json:"lukeEnergyRecoveryPercent"`
|
||||
FiendWarSquadCount int `json:"fiendWarSquadCount"`
|
||||
RoomFatigueCost int `json:"roomFatigueCost"`
|
||||
DailyFatigueResetHour int `json:"dailyFatigueResetHour"`
|
||||
AdventureGroupBonusPercent int `json:"adventureGroupBonusPercent"`
|
||||
RentalMaxReinforce int `json:"rentalMaxReinforce"`
|
||||
RentalMaxForge int `json:"rentalMaxForge"`
|
||||
ReviveByDungeon map[string]int `json:"reviveByDungeon"`
|
||||
AntonBlackFogRecoverySeconds int `json:"antonBlackFogRecoverySeconds"`
|
||||
AntonBlackFogActiveSeconds int `json:"antonBlackFogActiveSeconds"`
|
||||
AntonQuakeRecoverySeconds int `json:"antonQuakeRecoverySeconds"`
|
||||
AntonQuakeActiveSeconds int `json:"antonQuakeActiveSeconds"`
|
||||
AntonNavalOpenDelaySeconds int `json:"antonNavalOpenDelaySeconds"`
|
||||
AntonNavalRecoverySeconds int `json:"antonNavalRecoverySeconds"`
|
||||
AntonNavalActiveSeconds int `json:"antonNavalActiveSeconds"`
|
||||
LukeEnergyRecovery0Seconds int `json:"lukeEnergyRecovery0Seconds"`
|
||||
LukeEnergyRecovery1Seconds int `json:"lukeEnergyRecovery1Seconds"`
|
||||
LukeEnergyRecovery2Seconds int `json:"lukeEnergyRecovery2Seconds"`
|
||||
LukePhaseTimeoutPercent int `json:"lukePhaseTimeoutPercent"`
|
||||
FiendWarAreaLimitPercent int `json:"fiendWarAreaLimitPercent"`
|
||||
FiendWarDieImprisonPercent int `json:"fiendWarDieImprisonPercent"`
|
||||
SoloTeleportCooldownSeconds int `json:"soloTeleportCooldownSeconds"`
|
||||
SoloTeleportCooldownIndices string `json:"soloTeleportCooldownIndices"`
|
||||
AuctionStandardListingLimit int `json:"auctionStandardListingLimit"`
|
||||
AuctionPremiumListingLimit int `json:"auctionPremiumListingLimit"`
|
||||
AuctionStandardDurationHours int `json:"auctionStandardDurationHours"`
|
||||
AuctionPremiumDurationHours int `json:"auctionPremiumDurationHours"`
|
||||
AntonMemberMax int `json:"antonMemberMax"`
|
||||
AntonStartMinimumMembers int `json:"antonStartMinimumMembers"`
|
||||
AntonSingleStartMinimumMembers int `json:"antonSingleStartMinimumMembers"`
|
||||
AntonStartDelaySeconds int `json:"antonStartDelaySeconds"`
|
||||
AntonPhaseBreakSeconds int `json:"antonPhaseBreakSeconds"`
|
||||
AntonEntryCostItem int `json:"antonEntryCostItem"`
|
||||
AntonEntryCostCount int `json:"antonEntryCostCount"`
|
||||
AntonWeeklyEnterCountA int `json:"antonWeeklyEnterCountA"`
|
||||
AntonWeeklyEnterCountB int `json:"antonWeeklyEnterCountB"`
|
||||
AntonPhaseTimeoutSeconds string `json:"antonPhaseTimeoutSeconds"`
|
||||
LukeDailyAccountEnterLimit int `json:"lukeDailyAccountEnterLimit"`
|
||||
LukeSanctumTimerCount int `json:"lukeSanctumTimerCount"`
|
||||
LukeEntryCostItem int `json:"lukeEntryCostItem"`
|
||||
LukeEntryCostCount int `json:"lukeEntryCostCount"`
|
||||
FiendWarMemberMax int `json:"fiendWarMemberMax"`
|
||||
FiendWarStartMinimumMembers int `json:"fiendWarStartMinimumMembers"`
|
||||
FiendWarDisconnectWaitSeconds int `json:"fiendWarDisconnectWaitSeconds"`
|
||||
FiendWarEntryCostItem int `json:"fiendWarEntryCostItem"`
|
||||
FiendWarEntryCostCount int `json:"fiendWarEntryCostCount"`
|
||||
FiendWarRetry *bool `json:"fiendWarRetry"`
|
||||
FiendWarDailyEnterLimit int `json:"fiendWarDailyEnterLimit"`
|
||||
AuctionStandardFeePercent int `json:"auctionStandardFeePercent"`
|
||||
AuctionPremiumFeePercent int `json:"auctionPremiumFeePercent"`
|
||||
}
|
||||
|
||||
func GMSaveServerFeatures(data []byte) error {
|
||||
var values map[string]json.RawMessage
|
||||
if err := json.Unmarshal(data, &values); err != nil {
|
||||
return err
|
||||
}
|
||||
path := currentServerConfigPath("server-features.json")
|
||||
tmp := path + ".tmp"
|
||||
if err := os.WriteFile(tmp, data, 0o644); err != nil {
|
||||
return err
|
||||
}
|
||||
return os.Rename(tmp, path)
|
||||
}
|
||||
|
||||
func currentServerConfigPath(name string) string {
|
||||
candidates := []string{filepath.Join("config", name)}
|
||||
if executable, err := os.Executable(); err == nil {
|
||||
candidates = append(candidates,
|
||||
filepath.Join(filepath.Dir(executable), "..", "config", name),
|
||||
filepath.Join(filepath.Dir(executable), "config", name),
|
||||
)
|
||||
}
|
||||
for _, candidate := range candidates {
|
||||
if _, err := os.Stat(candidate); err == nil {
|
||||
return candidate
|
||||
}
|
||||
}
|
||||
return candidates[0]
|
||||
}
|
||||
|
||||
func currentServerFeatures() currentServerFeatureSettings {
|
||||
data, err := os.ReadFile(currentServerConfigPath("server-features.json"))
|
||||
if err != nil {
|
||||
return currentServerFeatureSettings{}
|
||||
}
|
||||
var settings currentServerFeatureSettings
|
||||
if err := json.Unmarshal(data, &settings); err != nil {
|
||||
return currentServerFeatureSettings{}
|
||||
}
|
||||
return settings
|
||||
}
|
||||
|
||||
func currentActivityEnabled(key string) bool {
|
||||
data, err := os.ReadFile(currentServerConfigPath("activity.json"))
|
||||
if err != nil {
|
||||
return true
|
||||
}
|
||||
var values map[string]bool
|
||||
if err := json.Unmarshal(data, &values); err != nil {
|
||||
return true
|
||||
}
|
||||
enabled, found := values[key]
|
||||
if !found {
|
||||
return true
|
||||
}
|
||||
return enabled
|
||||
}
|
||||
|
||||
func currentConfiguredAllDeadReturnDelay() time.Duration {
|
||||
const fallback = currentPartyDungeonAllDeadReturnDelay
|
||||
settings := currentServerFeatures()
|
||||
if settings.AllDeadReturnSeconds < 1 || settings.AllDeadReturnSeconds > 60 {
|
||||
return fallback
|
||||
}
|
||||
return time.Duration(settings.AllDeadReturnSeconds) * time.Second
|
||||
}
|
||||
|
||||
func currentConfiguredAllowFreeRevive() bool {
|
||||
settings := currentServerFeatures()
|
||||
if settings.AllowFreeRevive == nil {
|
||||
return currentDungeonUseCoinAllowFreeRevive
|
||||
}
|
||||
return *settings.AllowFreeRevive
|
||||
}
|
||||
|
||||
func currentConfiguredHellOrbChance() int {
|
||||
settings := currentServerFeatures()
|
||||
if settings.HellOrbChance < 0 || settings.HellOrbChance > currentDungeonHellOrbRollDenominator {
|
||||
return currentDungeonHellOrbChance
|
||||
}
|
||||
return settings.HellOrbChance
|
||||
}
|
||||
|
||||
func currentConfiguredHellDropChanceDenominator() int {
|
||||
settings := currentServerFeatures()
|
||||
if settings.HellDropChanceDenominator < 1 || settings.HellDropChanceDenominator > 1_000_000 {
|
||||
return currentHellPartyDropChanceDenominator
|
||||
}
|
||||
return settings.HellDropChanceDenominator
|
||||
}
|
||||
|
||||
func currentConfiguredAntonRaidAttackSeconds() int {
|
||||
settings := currentServerFeatures()
|
||||
if settings.AntonRaidAttackSeconds < 60 || settings.AntonRaidAttackSeconds > 24*60*60 {
|
||||
return antonRaidAttackSeconds
|
||||
}
|
||||
return settings.AntonRaidAttackSeconds
|
||||
}
|
||||
|
||||
func currentConfiguredLukeEnergyRecoveryPercent() int {
|
||||
settings := currentServerFeatures()
|
||||
if settings.LukeEnergyRecoveryPercent < 1 || settings.LukeEnergyRecoveryPercent > 1000 {
|
||||
return 100
|
||||
}
|
||||
return settings.LukeEnergyRecoveryPercent
|
||||
}
|
||||
|
||||
func currentConfiguredFiendWarSquadCount() int {
|
||||
settings := currentServerFeatures()
|
||||
if settings.FiendWarSquadCount < 1 || settings.FiendWarSquadCount > 8 {
|
||||
return currentFiendWarSquadCount
|
||||
}
|
||||
return settings.FiendWarSquadCount
|
||||
}
|
||||
|
||||
func currentConfiguredRoomFatigueCost() int64 {
|
||||
settings := currentServerFeatures()
|
||||
if settings.RoomFatigueCost < 0 || settings.RoomFatigueCost > 100 {
|
||||
return currentDungeonRoomFatigueCost
|
||||
}
|
||||
return int64(settings.RoomFatigueCost)
|
||||
}
|
||||
|
||||
func currentConfiguredDailyFatigueResetHour() int {
|
||||
settings := currentServerFeatures()
|
||||
if settings.DailyFatigueResetHour < 0 || settings.DailyFatigueResetHour > 23 {
|
||||
return 6
|
||||
}
|
||||
return settings.DailyFatigueResetHour
|
||||
}
|
||||
|
||||
func currentConfiguredAdventureGroupBonusPercent() int {
|
||||
settings := currentServerFeatures()
|
||||
if settings.AdventureGroupBonusPercent < 0 || settings.AdventureGroupBonusPercent > 1000 {
|
||||
return currentDungeonAdventureGroupDefaultClearBonusPercent
|
||||
}
|
||||
return settings.AdventureGroupBonusPercent
|
||||
}
|
||||
|
||||
func currentConfiguredRentalMaxReinforce() int {
|
||||
settings := currentServerFeatures()
|
||||
if settings.RentalMaxReinforce < 0 || settings.RentalMaxReinforce > 31 {
|
||||
return currentRentalMaxReinforce
|
||||
}
|
||||
return settings.RentalMaxReinforce
|
||||
}
|
||||
|
||||
func currentConfiguredRentalMaxForge() int {
|
||||
settings := currentServerFeatures()
|
||||
if settings.RentalMaxForge < 0 || settings.RentalMaxForge > 255 {
|
||||
return currentRentalMaxForge
|
||||
}
|
||||
return settings.RentalMaxForge
|
||||
}
|
||||
|
||||
func currentConfiguredDungeonReviveSeconds(dungeonID int64) (int, bool) {
|
||||
if dungeonID <= 0 {
|
||||
return 0, false
|
||||
}
|
||||
settings := currentServerFeatures()
|
||||
if settings.ReviveByDungeon == nil {
|
||||
return 0, false
|
||||
}
|
||||
value, found := settings.ReviveByDungeon[strconv.FormatInt(dungeonID, 10)]
|
||||
if !found || value < 1 || value > 86400 {
|
||||
return 0, false
|
||||
}
|
||||
return value, true
|
||||
}
|
||||
|
||||
func currentConfiguredDungeonReviveDelay(dungeonID int64) time.Duration {
|
||||
seconds, found := currentConfiguredDungeonReviveSeconds(dungeonID)
|
||||
if !found {
|
||||
return currentConfiguredRaidReviveDelay()
|
||||
}
|
||||
return time.Duration(seconds) * time.Second
|
||||
}
|
||||
|
||||
func currentAntonDuration(configured int, fallback time.Duration) time.Duration {
|
||||
if configured < 1 || configured > 86400 {
|
||||
return fallback
|
||||
}
|
||||
return time.Duration(configured) * time.Second
|
||||
}
|
||||
|
||||
func currentAntonBlackFogRecovery() time.Duration {
|
||||
return currentAntonDuration(currentServerFeatures().AntonBlackFogRecoverySeconds, antonBlackFogRecovery)
|
||||
}
|
||||
|
||||
func currentAntonBlackFogActive() time.Duration {
|
||||
return currentAntonDuration(currentServerFeatures().AntonBlackFogActiveSeconds, antonBlackFogActive)
|
||||
}
|
||||
|
||||
func currentAntonQuakeRecovery() time.Duration {
|
||||
return currentAntonDuration(currentServerFeatures().AntonQuakeRecoverySeconds, antonQuakeRecovery)
|
||||
}
|
||||
|
||||
func currentAntonQuakeActive() time.Duration {
|
||||
return currentAntonDuration(currentServerFeatures().AntonQuakeActiveSeconds, antonQuakeActive)
|
||||
}
|
||||
|
||||
func currentAntonNavalOpenDelay() time.Duration {
|
||||
return currentAntonDuration(currentServerFeatures().AntonNavalOpenDelaySeconds, antonNavalOpenDelay)
|
||||
}
|
||||
|
||||
func currentAntonNavalRecovery() time.Duration {
|
||||
return currentAntonDuration(currentServerFeatures().AntonNavalRecoverySeconds, antonNavalRecovery)
|
||||
}
|
||||
|
||||
func currentAntonNavalActive() time.Duration {
|
||||
return currentAntonDuration(currentServerFeatures().AntonNavalActiveSeconds, antonNavalActive)
|
||||
}
|
||||
|
||||
func currentLukeEnergyRecovery(tier int) time.Duration {
|
||||
if tier < 0 {
|
||||
tier = 0
|
||||
}
|
||||
if tier >= len(lukeEnergyControlRecovery) {
|
||||
tier = len(lukeEnergyControlRecovery) - 1
|
||||
}
|
||||
settings := currentServerFeatures()
|
||||
values := [...]int{
|
||||
settings.LukeEnergyRecovery0Seconds,
|
||||
settings.LukeEnergyRecovery1Seconds,
|
||||
settings.LukeEnergyRecovery2Seconds,
|
||||
}
|
||||
if values[tier] >= 1 && values[tier] <= 86400 {
|
||||
return time.Duration(values[tier]) * time.Second
|
||||
}
|
||||
percent := settings.LukeEnergyRecoveryPercent
|
||||
if percent < 1 || percent > 1000 {
|
||||
percent = 100
|
||||
}
|
||||
return time.Duration(int64(lukeEnergyControlRecovery[tier]) * int64(percent) / 100)
|
||||
}
|
||||
|
||||
func currentLukePhaseTimeoutPercent() int {
|
||||
percent := currentServerFeatures().LukePhaseTimeoutPercent
|
||||
if percent < 1 || percent > 1000 {
|
||||
return 100
|
||||
}
|
||||
return percent
|
||||
}
|
||||
|
||||
func currentFiendWarAreaLimitPercent() int {
|
||||
percent := currentServerFeatures().FiendWarAreaLimitPercent
|
||||
if percent < 1 || percent > 1000 {
|
||||
return 100
|
||||
}
|
||||
return percent
|
||||
}
|
||||
|
||||
func currentFiendWarDieImprisonPercent() int {
|
||||
percent := currentServerFeatures().FiendWarDieImprisonPercent
|
||||
if percent < 1 || percent > 1000 {
|
||||
return 100
|
||||
}
|
||||
return percent
|
||||
}
|
||||
|
||||
func currentConfiguredSoloTeleportCooldownSeconds() uint32 {
|
||||
seconds := currentServerFeatures().SoloTeleportCooldownSeconds
|
||||
if seconds < 1 || seconds > 86400 {
|
||||
return currentSoloTeleportCooldownSeconds
|
||||
}
|
||||
return uint32(seconds)
|
||||
}
|
||||
|
||||
func currentConfiguredSoloTeleportIndices() []byte {
|
||||
raw := strings.TrimSpace(currentServerFeatures().SoloTeleportCooldownIndices)
|
||||
if raw == "" {
|
||||
return nil
|
||||
}
|
||||
if strings.EqualFold(raw, "off") || strings.EqualFold(raw, "none") {
|
||||
return []byte{}
|
||||
}
|
||||
var indices []byte
|
||||
for _, field := range strings.Split(raw, ",") {
|
||||
value, err := strconv.ParseUint(strings.TrimSpace(field), 10, 8)
|
||||
if err == nil && currentSoloTeleportCooldownIndexAccepted(byte(value)) {
|
||||
indices = append(indices, byte(value))
|
||||
}
|
||||
}
|
||||
return indices
|
||||
}
|
||||
|
||||
func currentConfiguredAuctionListingLimit(premium bool) int {
|
||||
settings := currentServerFeatures()
|
||||
value := settings.AuctionStandardListingLimit
|
||||
if premium {
|
||||
value = settings.AuctionPremiumListingLimit
|
||||
}
|
||||
if value < 1 || value > 1000 {
|
||||
if premium {
|
||||
return currentAuctionPremiumListingLimit
|
||||
}
|
||||
return currentAuctionStandardListingLimit
|
||||
}
|
||||
return value
|
||||
}
|
||||
|
||||
func currentConfiguredAuctionDuration(premium bool) time.Duration {
|
||||
settings := currentServerFeatures()
|
||||
hours := settings.AuctionStandardDurationHours
|
||||
if premium {
|
||||
hours = settings.AuctionPremiumDurationHours
|
||||
}
|
||||
if hours < 1 || hours > 720 {
|
||||
if premium {
|
||||
return currentAuctionPremiumDuration
|
||||
}
|
||||
return currentAuctionStandardDuration
|
||||
}
|
||||
return time.Duration(hours) * time.Hour
|
||||
}
|
||||
|
||||
func currentConfiguredAuctionFeePercent(premium bool) int64 {
|
||||
settings := currentServerFeatures()
|
||||
value := settings.AuctionStandardFeePercent
|
||||
if premium {
|
||||
value = settings.AuctionPremiumFeePercent
|
||||
}
|
||||
if value <= 0 || value > 100 {
|
||||
return dnfauction.SaleFeePercentFor(premium)
|
||||
}
|
||||
return int64(value)
|
||||
}
|
||||
|
||||
// currentConfiguredRaidReviveDelay reads the optional runtime/config/
|
||||
// server-features.json written by the standalone server tool. It only changes
|
||||
// the server-side death watchdog; the current EXE still owns its ten-second
|
||||
// revive prompt.
|
||||
func currentConfiguredRaidReviveDelay() time.Duration {
|
||||
const fallback = currentDungeonDeathReturnDelay
|
||||
settings := currentServerFeatures()
|
||||
if settings.RaidReviveSeconds < 1 || settings.RaidReviveSeconds > 60 {
|
||||
return fallback
|
||||
}
|
||||
return time.Duration(settings.RaidReviveSeconds) * time.Second
|
||||
}
|
||||
|
||||
// currentConfiguredEquipmentRollMultiplier keeps the local test-end special
|
||||
// drop tuning (2x equipment rolls) configurable by the standalone server tool.
|
||||
func currentConfiguredEquipmentRollMultiplier() int {
|
||||
settings := currentServerFeatures()
|
||||
if settings.EquipmentRollMultiplier < 1 || settings.EquipmentRollMultiplier > 100 {
|
||||
return 1
|
||||
}
|
||||
return settings.EquipmentRollMultiplier
|
||||
}
|
||||
|
||||
// currentConfiguredEpicPieceRollMultiplier keeps the local test-end special
|
||||
// drop tuning (3x epic fragment rolls) configurable by the standalone tool.
|
||||
func currentConfiguredEpicPieceRollMultiplier() int {
|
||||
settings := currentServerFeatures()
|
||||
if settings.EpicPieceRollMultiplier < 1 || settings.EpicPieceRollMultiplier > 100 {
|
||||
return 1
|
||||
}
|
||||
return settings.EpicPieceRollMultiplier
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user