docs & feat: add license & attribution notice (Apache-2.0 / GPL-3.0) and core system enhancements
This commit is contained in:
1 parent
507836d367
commit
ce6aabfc55
47 files changed
+5674
-724
No files matched your search
+140
-33
@@ -699,8 +699,11 @@ func apiTeleport(w http.ResponseWriter, r *http.Request) {
|
||||
data.Position.RotY = *req.RotY
|
||||
}
|
||||
|
||||
data.SavePersistent()
|
||||
writeJSON(w, map[string]any{"message": "teleported successfully", "status": 200})
|
||||
if err := data.SavePersistentChecked(); err != nil {
|
||||
writeJSON(w, map[string]any{"error": "failed to save location: " + err.Error(), "status": 500})
|
||||
return
|
||||
}
|
||||
writeJSON(w, map[string]any{"message": "location saved", "status": 200})
|
||||
}
|
||||
|
||||
// apiGachabaseFetch proxies requests to hsr.gachabase.net to bypass browser CORS restrictions.
|
||||
@@ -828,7 +831,8 @@ func apiCommand(w http.ResponseWriter, r *http.Request) {
|
||||
|
||||
switch rootCmd {
|
||||
case "/heal":
|
||||
output = "[OK] Team HP, SP, and Energy fully restored."
|
||||
output = "Healing through this API is not implemented."
|
||||
success = false
|
||||
|
||||
case "/max":
|
||||
for _, av := range data.Avatars {
|
||||
@@ -866,53 +870,156 @@ func apiCommand(w http.ResponseWriter, r *http.Request) {
|
||||
}
|
||||
|
||||
case "/avatar":
|
||||
if len(parts) > 1 {
|
||||
aid, _ := strconv.ParseUint(parts[1], 10, 32)
|
||||
if av, exists := data.Avatars[uint32(aid)]; exists {
|
||||
if len(parts) > 2 {
|
||||
lvl, _ := strconv.ParseUint(parts[2], 10, 32)
|
||||
if lvl > 0 && lvl <= 80 {
|
||||
av.Level = uint32(lvl)
|
||||
}
|
||||
}
|
||||
if len(parts) > 3 {
|
||||
rank, _ := strconv.ParseUint(parts[3], 10, 32)
|
||||
av.Data.Rank = uint32(rank)
|
||||
}
|
||||
output = fmt.Sprintf("[OK] Avatar %d updated (Lv.%d, Rank %d).", aid, av.Level, av.Data.Rank)
|
||||
} else {
|
||||
output = fmt.Sprintf("[Error] Avatar ID %d not found in freesr-data.", aid)
|
||||
success = false
|
||||
if len(parts) < 3 || len(parts) > 4 {
|
||||
output, success = "Usage: /avatar <avatar_id> <level 1-80> [rank 0-6]", false
|
||||
break
|
||||
}
|
||||
aid, aidErr := strconv.ParseUint(parts[1], 10, 32)
|
||||
level, levelErr := strconv.ParseUint(parts[2], 10, 32)
|
||||
if aidErr != nil || aid == 0 || levelErr != nil || level < 1 || level > 80 {
|
||||
output, success = "Invalid avatar ID or level (1-80 required).", false
|
||||
break
|
||||
}
|
||||
levelValue := uint32(level)
|
||||
var rankValue *uint32
|
||||
if len(parts) == 4 {
|
||||
parsed, err := strconv.ParseUint(parts[3], 10, 32)
|
||||
if err != nil || parsed > 6 {
|
||||
output, success = "Invalid rank (0-6 required).", false
|
||||
break
|
||||
}
|
||||
rank := uint32(parsed)
|
||||
rankValue = &rank
|
||||
}
|
||||
if err := common.SaveAvatarProgress(uint32(aid), &levelValue, rankValue); err != nil {
|
||||
output, success = fmt.Sprintf("Cannot update avatar: %v", err), false
|
||||
} else {
|
||||
output = "Usage: /avatar <avatar_id> [level] [rank]"
|
||||
success = false
|
||||
output = fmt.Sprintf("Avatar %d saved. Reconnect the game to load the change.", aid)
|
||||
}
|
||||
|
||||
case "/give", "/item":
|
||||
output = "Giving items through this command is not implemented. Use the inventory editor."
|
||||
success = false
|
||||
|
||||
case "/unlockall", "/ua":
|
||||
sub := ""
|
||||
if len(parts) > 1 {
|
||||
itemID := parts[1]
|
||||
count := "1"
|
||||
sub = strings.ToLower(parts[1])
|
||||
}
|
||||
switch sub {
|
||||
case "warp":
|
||||
arg := "all"
|
||||
if len(parts) > 2 {
|
||||
count = parts[2]
|
||||
arg = strings.ToLower(parts[2])
|
||||
}
|
||||
output = fmt.Sprintf("[OK] Item %s x%s added to inventory.", itemID, count)
|
||||
} else {
|
||||
output = "Usage: /give <item_id> [count]"
|
||||
mode := 1
|
||||
switch arg {
|
||||
case "all", "on", "1", "true":
|
||||
mode = 1
|
||||
case "off", "0", "none", "disable", "false":
|
||||
mode = 0
|
||||
case "avatar", "character", "char", "2":
|
||||
mode = 2
|
||||
case "lightcone", "lc", "weapon", "3":
|
||||
mode = 3
|
||||
default:
|
||||
output = "Usage: /unlockall warp [all|avatar|lightcone|off]"
|
||||
success = false
|
||||
}
|
||||
if success {
|
||||
data.WarpUnlockMode = mode
|
||||
visible, visibilityErr := common.LoadVisibleGachaBanners(mode)
|
||||
if visibilityErr != nil {
|
||||
output = visibilityErr.Error()
|
||||
success = false
|
||||
break
|
||||
}
|
||||
count := len(visible)
|
||||
desc := "all warps"
|
||||
if mode == 0 {
|
||||
desc = "default active warps"
|
||||
} else if mode == 2 {
|
||||
desc = "character warps"
|
||||
} else if mode == 3 {
|
||||
desc = "lightcone warps"
|
||||
}
|
||||
output = fmt.Sprintf("[OK] Set %s (%d banners visible). Reopen Warp to refresh.", desc, count)
|
||||
}
|
||||
case "all":
|
||||
data.WarpUnlockMode = 1
|
||||
visible, visibilityErr := common.LoadVisibleGachaBanners(1)
|
||||
if visibilityErr != nil {
|
||||
output = visibilityErr.Error()
|
||||
success = false
|
||||
break
|
||||
}
|
||||
count := len(visible)
|
||||
output = fmt.Sprintf("[OK] Selected all %d verified warps. Reopen Warp to refresh.", count)
|
||||
case "skin":
|
||||
output = "Skin unlocking is not implemented by this command."
|
||||
success = false
|
||||
default:
|
||||
output = "Usage: /unlockall [warp|all|skin]\n /unlockall warp [all|avatar|lightcone|off]"
|
||||
success = false
|
||||
}
|
||||
|
||||
case "/reload":
|
||||
sub := ""
|
||||
if len(parts) > 1 {
|
||||
sub = strings.ToLower(parts[1])
|
||||
}
|
||||
switch sub {
|
||||
case "banner", "banners":
|
||||
if err := common.ReloadBanners(); err != nil {
|
||||
output = fmt.Sprintf("[Error] Failed to reload banners: %v", err)
|
||||
success = false
|
||||
} else {
|
||||
visible, visibilityErr := common.LoadVisibleGachaBanners(data.WarpUnlockMode)
|
||||
if visibilityErr != nil {
|
||||
output = visibilityErr.Error()
|
||||
success = false
|
||||
break
|
||||
}
|
||||
count := len(visible)
|
||||
output = fmt.Sprintf("[OK] Banner configurations reloaded successfully (%d visible in current mode).", count)
|
||||
}
|
||||
default:
|
||||
output = "Usage: /reload [banner]"
|
||||
success = false
|
||||
}
|
||||
|
||||
case "/help":
|
||||
output = "/faketime [status|off|Unix seconds|RFC3339 with timezone] - Set game calendar time\n"
|
||||
output += "Available GM Commands:\n /heal - Fully restore team HP, SP, and Energy\n /max - Set all avatars to Max Lv.80 E6\n /teleport <plane_id> [floor_id] - Teleport to scene\n /avatar <id> [level] [rank] - Modify avatar\n /give <item_id> [count] - Add items to inventory\n /clear lineup - Clear active lineup slots"
|
||||
output += "Available GM Commands:\n /max - Set all avatars to Max Lv.80 E6\n /teleport <plane_id> [floor_id] - Set scene\n /avatar <id> <level> [rank] - Modify avatar\n /clear lineup - Clear active lineup slots\n /unlockall warp [all|avatar|lightcone|off] - Toggle unlocked gacha banners\n /reload banner - Reload banner configurations"
|
||||
|
||||
default:
|
||||
output = fmt.Sprintf("[OK] Custom command '%s' dispatched to server.", cmd)
|
||||
output = fmt.Sprintf("Unknown command: %s", cmd)
|
||||
success = false
|
||||
}
|
||||
|
||||
raw, _ := json.MarshalIndent(data, "", " ")
|
||||
_ = os.WriteFile("freesr-data.json", raw, 0o644)
|
||||
data.SavePersistent()
|
||||
// Banner commands only patch their own persistent setting. Rewriting the
|
||||
// complete imported roster here can overwrite concurrent inventory updates.
|
||||
if rootCmd == "/unlockall" || rootCmd == "/ua" || rootCmd == "/reload" {
|
||||
if success && rootCmd != "/reload" {
|
||||
mode, _ := json.Marshal(data.WarpUnlockMode)
|
||||
if err := common.PatchPersistentFields(map[string]json.RawMessage{"warp_unlock_mode": mode}); err != nil {
|
||||
success = false
|
||||
output = err.Error()
|
||||
}
|
||||
}
|
||||
} else if success && rootCmd != "/help" && rootCmd != "/avatar" {
|
||||
raw, err := json.MarshalIndent(data, "", " ")
|
||||
if err == nil {
|
||||
err = os.WriteFile("freesr-data.json", raw, 0o644)
|
||||
}
|
||||
if err == nil {
|
||||
err = data.SavePersistentChecked()
|
||||
}
|
||||
if err != nil {
|
||||
success = false
|
||||
output = err.Error()
|
||||
}
|
||||
}
|
||||
|
||||
Log(fmt.Sprintf("[GM Command] %s -> %s", cmd, output))
|
||||
|
||||
|
||||
Reference in new issue
Block a user