首页
学习
活动
专区
圈层
工具
发布
社区首页 >专栏 >ACNH MobileSpawner - 动物森友会实时修改与岛编辑工具

ACNH MobileSpawner - 动物森友会实时修改与岛编辑工具

原创
作者头像
qife122
发布2026-01-19 10:34:00
发布2026-01-19 10:34:00
6220
举报

项目标题与描述

ACNH MobileSpawner 是一个专为《集合啦!动物森友会》(Animal Crossing: New Horizons)开发的多功能跨平台工具。该项目基于 Unity 引擎构建,旨在让玩家无需手动在 PC 上编辑存档,直接在游戏过程中进行实时修改。支持平台包括 Windows、Mac、Linux、Android 和 iOS。

注意:使用本工具需要 Switch 主机运行自制固件,并安装 sys-botbaseUSB-Botbase 系统模块。

功能特性

  • 物品注入与删除:支持为所有 1-8 号玩家注入或删除背包中的物品。
  • 资源修改:可更改银行中的铃钱和里程数,以及钱包(背包)中的铃钱。
  • 村民编辑与替换:使用完善的村民数据库更改或替换岛屿上的居民。
  • 大头菜价格调整:修改大头菜的买入/卖出价格及其波动。
  • 地图物品放置与批量生成:在地图上放置物品或进行批量生成,应用内提供预设方案。支持查找和替换物品。
  • 内部物品生成:可生成游戏内部物品(如甜甜圈),需注意这些物品可能影响其他玩家体验。
  • 原始 RAM 十六进制编辑:支持编辑 Switch 任意游戏的原始 RAM 字节,不仅限于《动物森友会》。
  • 地图清理:清除地图上的特定物品,如杂草、树枝、栅栏、灌木、花朵、树木、石头、木材、岩石材料、腐烂大头菜等。
  • 文件保存与共享:支持保存、分享和加载特定的《动物森友会》文件类型,如 *.nhi(背包)、*.nhv(村民)和 *.nhvh(村民房屋)。
  • 物品刷新与访客记录:刷新地面物品,并记录刷新器运行期间到访的玩家。
  • 数值冻结:冻结特定数值(如村民、背包、地图等)。
  • 传送点创建:创建传送点,方便在常用区域间快速移动。

安装指南

系统要求

  • 目标设备:运行 Nintendo Switch 自制固件。
  • 必需模块:Switch 端需安装 sys-botbaseUSB-Botbase
  • 运行平台:Windows、macOS、Linux、Android 或 iOS。

获取应用

  • 可直接下载 已编译的发行版 适用于各平台。
  • iOS 版本为自动构建,未经充分测试,但有用户反馈可正常使用。

使用说明

基础连接与操作

  1. 确保 Switch 与运行本应用的设备在同一网络(对于网络连接方式)。
  2. 在应用中配置正确的 Switch IP 地址和端口(默认为 192.168.0.1:6000)。
  3. 连接成功后,即可使用各项功能。

核心功能示例

背包物品管理
代码语言:csharp
复制
// 从 UI_ACItemGrid 获取当前背包物品列表
List<Item> items = UI_ACItemGrid.LastInstanceOfItemGrid.Items;

// 设置特定背包槽位的物品
Item newItem = new Item(Item.NONE);
newItem.ItemId = 0x0A3D; // 示例物品ID
UI_ACItemGrid.LastInstanceOfItemGrid.SetItemAt(newItem, index, true);
村民数据读取与写入
代码语言:csharp
复制
// 读取村民数据
byte[] villagerData = connection.ReadBytes(UI_Villager.CurrentVillagerAddress, Villager2.SIZE);
Villager2 villager = new Villager2(villagerData);

// 写入村民数据
Villager2 newVillager = new Villager2();
// ... 配置村民数据
connection.WriteBytes(newVillager.Data, UI_Villager.CurrentVillagerAddress);
地图物品编辑
代码语言:csharp
复制
// 获取地图物品层
FieldItemManager items = ...; // 从游戏内存读取
FieldItemLayer layer = items.Layer1;

// 更新地图上的物品块
FieldItemBlock block = new FieldItemBlock(layer, x, y);
block.UpdateItem(newItem);

// 将修改写回游戏
byte[] layerData = layer.GetLayer();
connection.WriteBytes(layerData, UI_MapTerrain.CurrentMapAddress);
时间与速度修改
代码语言:csharp
复制
// 冻结游戏时间
connection.WriteBytes(BitConverter.GetBytes(UI_TimeSpeed.FreezeTimeValue), 
                     OffsetHelper.TimeAddress, RWMethod.Main);

// 修改行走速度
uint walkSpeedValue = UI_TimeSpeed.WalkSteps[2]; // 选择速度等级
connection.WriteBytes(BitConverter.GetBytes(walkSpeedValue), 
                     OffsetHelper.WalkSpeedOffset, RWMethod.Main);

更多帮助

核心代码

以下是项目中部分关键组件的核心代码及注释:

1. 背包物品网格管理 (UI_ACItemGrid.cs)

代码语言:csharp
复制
using NHSE.Core;
using NHSE.Injection;
using UnityEngine;

public class UI_ACItemGrid : MonoBehaviour
{
    public readonly int MAXITEMS = 40; // 背包最大容量
    
    // 当前选中的背包槽位
    public int CurrentSelected { get; private set; }
    
    // 物品列表
    [HideInInspector]
    public List<Item> Items = new List<Item>();
    
    private List<UI_ACItem> uiitems; // UI 物品组件列表
    
    // 设置指定槽位的物品
    public void SetItemAt(Item item, int index, bool updateImmediately)
    {
        if (index < 0 || index >= Items.Count)
            return;
            
        Items[index] = item;
        uiitems[index].Assign(item);
        
        if (updateImmediately)
            WriteItemsToGame(); // 立即写入游戏
    }
    
    // 将修改后的物品列表写入游戏内存
    private void WriteItemsToGame()
    {
        byte[] itemBytes = new byte[Items.Count * Item.SIZE];
        for (int i = 0; i < Items.Count; i++)
            Array.Copy(Items[i].ToBytesClass(), 0, itemBytes, i * Item.SIZE, Item.SIZE);
            
        IRAMReadWriter connection = GetCurrentlyActiveReadWriter();
        uint offset = (uint)(SysBotController.CurrentOffsetFirstPlayerUInt + 
                           PocketInjector.shift + 
                           ((uint)OffsetHelper.PlayerSize * UI_Settings.GetPlayerIndex()));
        connection.WriteBytes(itemBytes, offset);
    }
}

2. 游戏手柄输入处理 (SwitchUIController.cs)

代码语言:csharp
复制
using NHSE.Injection;
using System.Collections.Concurrent;
using System.Threading.Tasks;

public class SwitchUIController : MonoBehaviour
{
    private ConcurrentQueue<SysBotExecution> ExecutionQueue = new ConcurrentQueue<SysBotExecution>();
    
    // 按下按钮
    public void Press(SwitchButton b, bool up)
    {
        ExecutionQueue.Enqueue(new SysBotExecution()
        {
            PType = up ? PressType.ButtonRelease : PressType.ButtonPress,
            ButtonToPress = b
        });
    }
    
    // 设置摇杆位置
    public void SetStick(SwitchStick s, short x, short y)
    {
        ExecutionQueue.Enqueue(new SysBotExecution()
        {
            PType = PressType.Joystick,
            StickToMove = s,
            X = x,
            Y = y
        });
    }
    
    // 处理命令队列
    public async Task DoSocketQueue(bool isNetwork, CancellationToken token)
    {
        while (!token.IsCancellationRequested)
        {
            if (ExecutionQueue.TryDequeue(out var item))
            {
                byte[] command = Array.Empty<byte>();
                switch (item.PType)
                {
                    case PressType.ButtonPress: 
                        command = SwitchCommand.Hold(item.ButtonToPress, isNetwork); 
                        break;
                    case PressType.ButtonRelease: 
                        command = SwitchCommand.Release(item.ButtonToPress, isNetwork); 
                        break;
                    case PressType.Joystick: 
                        command = SwitchCommand.SetStick(item.StickToMove, item.X, item.Y); 
                        break;
                }
                try { Connection.CurrentConnection.SendBytes(command); } catch { }
            }
            await Task.Delay(1, token).ConfigureAwait(false);
        }
    }
}

3. 地图图形生成器 (MapGraphicGenerator.cs)

代码语言:csharp
复制
using NHSE.Core;
using UnityEngine;

public class MapGraphicGenerator 
{
    private readonly FieldItemManager ItemManager;
    private readonly NHSE.Core.TerrainLayer Terrain;
    public Texture2D MapBackgroundImage { get; private set; }
    
    public MapGraphicGenerator(FieldItemManager items, NHSE.Core.TerrainLayer terrain, 
                              ushort plazaX, ushort plazaY, Building[] buildings)
    {
        ItemManager = items;
        Terrain = terrain;
        MapBackgroundImage = new Texture2D(Terrain.MaxWidth, Terrain.MaxHeight);
        
        // 绘制地形(河流和高度)
        for (int y = 0; y < Terrain.MaxHeight; y++)
        {
            for (int x = 0; x < Terrain.MaxWidth; x++)
            {
                var pxl = Terrain.GetTileColorRGB(x, y);
                MapBackgroundImage.SetPixel(x, y, new Color32(pxl.R, pxl.G, pxl.B, pxl.A));
            }
        }
        MapBackgroundImage.Apply();
    }
    
    // 生成包含物品的地图纹理
    public Texture2D GenerateItemLayerTexture(int layerIndex)
    {
        var layer = layerIndex == 0 ? ItemManager.Layer1 : ItemManager.Layer2;
        Texture2D texture = new Texture2D(layer.MaxWidth, layer.MaxHeight);
        
        for (int y = 0; y < layer.MaxHeight; y++)
        {
            for (int x = 0; x < layer.MaxWidth; x++)
            {
                Item item = layer.GetTile(x, y);
                Color color = item.IsNone ? Color.clear : GetItemColor(item);
                texture.SetPixel(x, y, color);
            }
        }
        texture.Apply();
        return texture;
    }
}

4. 村民数据管理 (UI_Villager.cs)

代码语言:csharp
复制
using NHSE.Core;
using System.Collections.Generic;
using UnityEngine;

public class UI_Villager : IUI_Additional
{
    const int VillagersSize = Villager2.SIZE * 10; // 10个村民
    
    private Villager2 loadedVillager;
    private List<Villager2> loadedVillagerShellsList;
    
    // 读取村民数据
    public void FetchVillagerData(int villagerIndex)
    {
        currentlyLoadedVillagerIndex = villagerIndex;
        uint address = CurrentVillagerAddress + (uint)(villagerIndex * Villager2.SIZE);
        
        byte[] villagerData = CurrentConnection.ReadBytes(address, Villager2.SIZE);
        loadedVillager = new Villager2(villagerData);
        
        UpdateVillagerUI();
    }
    
    // 写入村民数据到游戏
    public void WriteVillagerDataVillager(Villager2 villager)
    {
        if (currentlyLoadedVillagerIndex < 0)
            return;
            
        uint address = CurrentVillagerAddress + (uint)(currentlyLoadedVillagerIndex * Villager2.SIZE);
        CurrentConnection.WriteBytes(villager.Data, address);
        
        loadedVillager = villager;
        UpdateVillagerUI();
    }
    
    // 更新村民UI显示
    private void UpdateVillagerUI()
    {
        if (loadedVillager == null)
            return;
            
        string internalName = loadedVillager.InternalName;
        VillagerName.text = GameInfo.Strings.GetVillager(internalName);
        
        // 加载村民头像
        Texture2D villagerTexture = SpriteBehaviour.PullTextureFromParser(villagerSprites, internalName);
        MainVillagerTexture.texture = villagerTexture;
    }
}

5. 摇杆输入组件 (Joystick.cs)

代码语言:csharp
复制
using UnityEngine;
using UnityEngine.EventSystems;

public class Joystick : MonoBehaviour, IPointerDownHandler, IDragHandler, IPointerUpHandler
{
    public float Horizontal { get { return (snapX) ? SnapFloat(input.x, AxisOptions.Horizontal) : input.x; } }
    public float Vertical { get { return (snapY) ? SnapFloat(input.y, AxisOptions.Vertical) : input.y; } }
    public Vector2 Direction { get { return new Vector2(Horizontal, Vertical); } }
    
    public delegate void UpdateStick(Vector2 direction);
    public UpdateStick OnUpdateStick;
    public delegate void InteractStick(bool interacting);
    public InteractStick OnInteractStick;
    
    // 处理指针按下事件
    public override void OnPointerDown(PointerEventData eventData)
    {
        input = Vector2.zero;
        handle.anchoredPosition = Vector2.zero;
        OnInteractStick?.Invoke(true);
    }
    
    // 处理拖拽事件
    public override void OnDrag(PointerEventData eventData)
    {
        cam = null;
        if (canvas.renderMode == RenderMode.ScreenSpaceCamera)
            cam = canvas.worldCamera;
        
        Vector2 position = RectTransformUtility.WorldToScreenPoint(cam, background.position);
        Vector2 radius = background.sizeDelta / 2;
        input = (eventData.position - position) / (radius * canvas.scaleFactor);
        FormatInput();
        HandleInput(input.magnitude, input.normalized, radius, cam);
        OnUpdateStick?.Invoke(Direction);
    }
    
    // 处理指针释放事件
    public override void OnPointerUp(PointerEventData eventData)
    {
        input = Vector2.zero;
        handle.anchoredPosition = Vector2.zero;
        OnUpdateStick?.Invoke(Direction);
        OnInteractStick?.Invoke(false);
    }
}

免责声明:请负责任地使用本工具,不要利用内部物品破坏其他玩家的游戏体验,也不要在本地或在线游戏中使用这些物品进行交易。

/l+B+Emd3f6klEWwza4S0rESvcdto6ak5WE7ry7XXzc=

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 项目标题与描述
  • 功能特性
  • 安装指南
    • 系统要求
    • 获取应用
  • 使用说明
    • 基础连接与操作
    • 核心功能示例
      • 背包物品管理
      • 村民数据读取与写入
      • 地图物品编辑
      • 时间与速度修改
    • 更多帮助
  • 核心代码
    • 1. 背包物品网格管理 (UI_ACItemGrid.cs)
    • 2. 游戏手柄输入处理 (SwitchUIController.cs)
    • 3. 地图图形生成器 (MapGraphicGenerator.cs)
    • 4. 村民数据管理 (UI_Villager.cs)
    • 5. 摇杆输入组件 (Joystick.cs)
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档