<?xml version="1.0"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en">
	<id>https://ocr.michiyo.me/w/index.php?action=history&amp;feed=atom&amp;title=Tutorial%2Fmodding_architecture%2Fzh</id>
	<title>Tutorial/modding architecture/zh - Revision history</title>
	<link rel="self" type="application/atom+xml" href="https://ocr.michiyo.me/w/index.php?action=history&amp;feed=atom&amp;title=Tutorial%2Fmodding_architecture%2Fzh"/>
	<link rel="alternate" type="text/html" href="https://ocr.michiyo.me/w/index.php?title=Tutorial/modding_architecture/zh&amp;action=history"/>
	<updated>2026-08-24T15:14:38Z</updated>
	<subtitle>Revision history for this page on the wiki</subtitle>
	<generator>MediaWiki 1.43.9</generator>
	<entry>
		<id>https://ocr.michiyo.me/w/index.php?title=Tutorial/modding_architecture/zh&amp;diff=1364&amp;oldid=prev</id>
		<title>imported&gt;OCDoc Import: Imported from legacy OpenComputers documentation at ocdoc.cil.li</title>
		<link rel="alternate" type="text/html" href="https://ocr.michiyo.me/w/index.php?title=Tutorial/modding_architecture/zh&amp;diff=1364&amp;oldid=prev"/>
		<updated>2026-08-24T08:08:27Z</updated>

		<summary type="html">&lt;p&gt;Imported from legacy OpenComputers documentation at ocdoc.cil.li&lt;/p&gt;
&lt;p&gt;&lt;b&gt;New page&lt;/b&gt;&lt;/p&gt;&lt;div&gt;= 模组开发：自定义架构 =&lt;br /&gt;
&lt;br /&gt;
在此文章中我会讲解OC模组的架构是如何工作的，以及如何添加自定义架构。一句警告：架构的实现&amp;#039;&amp;#039;&amp;#039;并非易事&amp;#039;&amp;#039;&amp;#039;，别指望着轻而易举就能完成。&lt;br /&gt;
&lt;br /&gt;
== 架构是什么？ ==&lt;br /&gt;
&lt;br /&gt;
首先让我们来申明OC模组语境下的“架构”是什么。架构指将某种代码执行器（以下称虚拟机）和OC模组的组件/Minecraft结合起来的程序。OC将组件逻辑与电脑逻辑严格分开。换言之，组件（例如显卡）不知道它自身在使用什么架构。反过来，架构也不知道组件如何工作。传递的一切信息都由&amp;#039;&amp;#039;&amp;#039;执行机&amp;#039;&amp;#039;&amp;#039;处理。执行机驱动架构，并提供回调函数使架构能与外界通信。&lt;br /&gt;
&lt;br /&gt;
== 使用架构 ==&lt;br /&gt;
&lt;br /&gt;
为了让内容不那么难以理解，这里将讲解如何实际&amp;#039;&amp;#039;&amp;#039;应用&amp;#039;&amp;#039;&amp;#039;架构。这大概能让读者更好地理解架构实现是怎么融入OC模组生态的。要使用架构，则必须创建一个使用此架构的执行机。&lt;br /&gt;
&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;注意：&amp;#039;&amp;#039;&amp;#039;OC 1.4版本后，附属模组可以注册通过CPU提供的架构，因此你无需添加一种电脑方块/物品了。可以通过手持CPU时潜行右键单击来切换其提供的架构。&lt;br /&gt;
&lt;br /&gt;
执行机封装了架构，并负责线程调度、信号队列、网络连接等。执行机创建好以后，你只需每tick调用一次`update()`函数（还可能需要向其传递一些调用，例如`start()`）。&lt;br /&gt;
&lt;br /&gt;
== 生命周期 ==&lt;br /&gt;
&lt;br /&gt;
架构的生命周期大致为：实例化，`initialize()`，反复执行`runThreaded()` / `runSynchronized()`，`close()` [, 转到 `initialize()`]。&lt;br /&gt;
&lt;br /&gt;
* 执行机被创建时，架构即被创建。 - 执行机启动或重启时，会要求`initialize()`自身。通常来说代表着创建底层虚拟机。 - 驱动架构的标准方法是通过`runThreaded()`函数，它由执行器线程调用。架构的状态应在此处处理。其返回值类型被执行机用于调度。&amp;#039;&amp;#039;&amp;#039;注意：&amp;#039;&amp;#039;&amp;#039;此方法不应抛出异常。你有责任处理所有错误，并在需要的时候将它们转换为代表报错的返回值。 - 需要有一个特殊执行结果来表示进行“同步调用”。这个返回值会告诉执行机下次需要用`runSynchronized()`来驱动架构。这种调用&amp;#039;&amp;#039;&amp;#039;一定会由MC服务端线程执行&amp;#039;&amp;#039;&amp;#039;，代表着可以安全地在此回调函数中与世界交互。 - 执行机停止时会调用`close()`函数。然后释放所有打开的资源。&lt;br /&gt;
&lt;br /&gt;
== 提供上下文 ==&lt;br /&gt;
&lt;br /&gt;
在最简单的样例中，每次调用`runThreaded()`时在你的虚拟机中仅仅进行若干`run`调用。不过这样做实际用处不大，因为你会想要以某种方式与外界通信。为了实现此功能，需要将与组件的通信提供给虚拟机。你需要在虚拟机内定义用于与执行机API通信的API（例如：`components()`和`invoke()`）。&lt;br /&gt;
&lt;br /&gt;
== 同步调用与调用上限 ==&lt;br /&gt;
&lt;br /&gt;
组件可能有一些回调函数声明为“直接调用”，此外它们可能还会定义“调用上限”。默认情况下，所有的组件回调函数都是&amp;#039;&amp;#039;&amp;#039;同步调用&amp;#039;&amp;#039;&amp;#039;，即架构必须保证这些函数只能由`runSynchronized()`调用。 直接调用的调用上限限制了单个执行机每tick调用某一个函数的次数。限制本身由执行机的`invoke`方法确保实现，此方法会在调用次数过多时抛出`LimitReachedException`异常。此时架构应当短暂休眠，或者改为执行非同步调用。&lt;br /&gt;
&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;注意：&amp;#039;&amp;#039;&amp;#039;在写这段内容的时候，我发现我忘记了把一些执行检查所需的方法放入API中。这将在下一个API更新中得到修复，使这些方法在`Component`接口中可用。现在的话，要么将它们反射进去，要么从OC源码自行构建模组。我对此表示抱歉。&lt;br /&gt;
&lt;br /&gt;
== 样例代码 ==&lt;br /&gt;
&lt;br /&gt;
假设你有能提供以下接口的虚拟机：&lt;br /&gt;
&lt;br /&gt;
```java /**虚拟机自身。这里的仅为一个样例，不是“真的”接口。*/ public interface PseudoVM {&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;Object[] run(Object[] args) throws Exception;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;void setApiFunction(String name, PseudoNativeFunction value);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/**定义了主机提供的回调的接口。*/ public interface PseudoNativeFunction {&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;Object invoke(Object[] args);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
} ```&lt;br /&gt;
&lt;br /&gt;
一个简单的架构实现大概看起来像这样子：&lt;br /&gt;
&lt;br /&gt;
```java /**这是你实现的类；这里的架构来自OC的API。*/ @Architecture.Name(&amp;quot;Pseudolang&amp;quot;) public class PseudoArchitecture implements Architecture {&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;private final Machine machine;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;private PseudoVM vm;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;/**构造函数的签名必须与此处完全一致。*/&lt;br /&gt;
public PseudoArchitecture(Machine machine) {&lt;br /&gt;
  this.machine = machine;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;public boolean isInitialized() { return true; }&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;public void recomputeMemory() {}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;public boolean initialize() {&lt;br /&gt;
  //在此处新建虚拟机，并在里面注册你想要的所有API回调函数。&lt;br /&gt;
  vm = new PseudoVM();&lt;br /&gt;
  vm.setApiFunction(&amp;quot;invoke&amp;quot;, new PseudoNativeFunction() {&lt;br /&gt;
    public Object invoke(Object[] args) {&lt;br /&gt;
      final String address = (String)args[0];&lt;br /&gt;
      final String method = (String)args[1];&lt;br /&gt;
      final Object[] params = (Object[])args[2];&lt;br /&gt;
      try {&lt;br /&gt;
        return new Object[]{true, machine.invoke(address, method, params)};&lt;br /&gt;
      }&lt;br /&gt;
      catch (e LimitReachedException) {&lt;br /&gt;
        //这里的执行逻辑也可用于休眠/执行同步调用。&lt;br /&gt;
        //在此样例中我们遵循这样的协议：&lt;br /&gt;
        //成功时返回(true,某物)，到达上限时返回(false)。&lt;br /&gt;
        //此后虚拟机中运行的脚本需要将控制权交还给&lt;br /&gt;
        //初始化了当前执行的任务的调用者（例如，若支持的话&lt;br /&gt;
        //可以yield，或者在事件驱动的系统中直接return）&lt;br /&gt;
        return new Object[]{false};&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
  });&lt;br /&gt;
  vm.setApiFunction(&amp;quot;isDirect&amp;quot;, new PseudoNativeFunction() {&lt;br /&gt;
    public Object invoke(Object[] args) {&lt;br /&gt;
      final String address = (String)args[0];&lt;br /&gt;
      final String method = (String)args[1];&lt;br /&gt;
      final Node node = machine.node().network().node(address);&lt;br /&gt;
      if (node instanceof Component) {&lt;br /&gt;
        final Component component = (Component) node;&lt;br /&gt;
        if (component.canBeSeenFrom(machine.node())) {&lt;br /&gt;
          final Callback callback = machine.methods(node.host()).get(method);&lt;br /&gt;
          if (callback != null) {&lt;br /&gt;
            return callback.direct();&lt;br /&gt;
          }&lt;br /&gt;
        }&lt;br /&gt;
      }&lt;br /&gt;
      return false;&lt;br /&gt;
    }&lt;br /&gt;
  });&lt;br /&gt;
  // ... 更多回调。&lt;br /&gt;
  return true;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;void close() {&lt;br /&gt;
  vm = null;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;ExecutionResult runThreaded(boolean isSynchronizedReturn) {&lt;br /&gt;
  //在此处执行所需步骤。通常你会希望通过将队列中下一个信号传递给&lt;br /&gt;
  //虚拟机的方式来唤醒它，但你也可能会选择让你的虚拟机手动拉取信号。&lt;br /&gt;
  try {&lt;br /&gt;
    final Signal signal;&lt;br /&gt;
    if (isSynchronizedReturn) {&lt;br /&gt;
      //正在从同步调用中返回时不要拉取信号！因为我们正在执行其他事情。&lt;br /&gt;
      signal = null;&lt;br /&gt;
    }&lt;br /&gt;
    else {&lt;br /&gt;
      signal = machine.popSignal();&lt;br /&gt;
    }&lt;br /&gt;
    final Object[] result;&lt;br /&gt;
    if (signal != null) {&lt;br /&gt;
      result = vm.run(new Object[]{signal.name(), signal.args()});&lt;br /&gt;
    }&lt;br /&gt;
    else {&lt;br /&gt;
      result = vm.run(null);&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;    //你可能会想定义一些内部协议，用以决定何时执行同步调用。&lt;br /&gt;
    //假设我们希望虚拟机在出现待决定的同步调用时返回数字值，代表休眠&lt;br /&gt;
    //或者返回布尔值，代表关机/重启或其他东西。&lt;br /&gt;
    if (result != null) {&lt;br /&gt;
      if (result[0] instanceof Boolean) {&lt;br /&gt;
        return new ExecutionResult.Shutdown((Boolean)result[0]);&lt;br /&gt;
      }&lt;br /&gt;
      if (result[0] instanceof Integer) {&lt;br /&gt;
        return new ExecutionResult.Sleep((Integer)result[0]);&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
    //若返回此值，下次&amp;#039;resume&amp;#039;时会调用runSynchronized。&lt;br /&gt;
    //此次调用后的下次对runThreaded函数的调用中&lt;br /&gt;
    //isSynchronizedReturn参数将会设定为true。&lt;br /&gt;
    return new ExecutionResult.SynchronizedCall();&lt;br /&gt;
  }&lt;br /&gt;
  catch (Throwable t) {&lt;br /&gt;
    return new ExecutionResult.Error(t.toString);&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;void runSynchronized() {&lt;br /&gt;
  //同步调用在MC的服务端线程中执行，让回调与世界交互更方便&lt;br /&gt;
  //（因为它们之间的同步由执行机/架构完成）&lt;br /&gt;
  //这意味着若虚拟机中的代码开始了一次同步调用，就需要&amp;#039;&amp;#039;暂停&amp;#039;&amp;#039;&lt;br /&gt;
  //并且放弃对主机的控制，然后我们切换到同步调用模式（参看runThreaded），&lt;br /&gt;
  //并等待MC服务端线程，接着再进行实际的调用。&lt;br /&gt;
  //可以在runThread中传递调用所需的信息，将其存储在架构中，&lt;br /&gt;
  //然后在此处直接进行调用。&lt;br /&gt;
  //对此样例而言，让我们假定状态信息存储于虚拟机内部，并且&lt;br /&gt;
  //下次resume使其进行&amp;#039;&amp;#039;实际&amp;#039;&amp;#039;调用。下面给出了处理它们的伪代码。&lt;br /&gt;
  vm.run(null);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;void onConnect() {}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;//用这行代码加载虚拟机状态，假如虚拟机可持续。&lt;br /&gt;
void load(NBTTagCompound nbt) {}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;//用这行代码保存虚拟机状态，假如虚拟机可持续。&lt;br /&gt;
void save(NBTTagCompound nbt) {}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
} ```&lt;br /&gt;
&lt;br /&gt;
一些用于在虚拟机中处理同步调用的伪代码：&lt;br /&gt;
&lt;br /&gt;
```scala private def invokeSynchronous(address, method, ...) {&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;yield; //此处为返回到runThreaded()的地方。&lt;br /&gt;
 //此处为进入runSynchronized();的地方&lt;br /&gt;
val result = native.invoke(address, method, ...);&lt;br /&gt;
//查看initialize()中invoke的定义以获取结果值的信息。&lt;br /&gt;
yield; //并返回runSynchronized();&lt;br /&gt;
//并且下一个runThreaded()又进入了。&lt;br /&gt;
return result[1];&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
} private def invokeDirect(address, method, ...) {&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;val result = native.invoke(address, method, ...);&lt;br /&gt;
//查看initialize()中invoke的定义以获取结果值的信息。&lt;br /&gt;
if (result[0] == true) {&lt;br /&gt;
  return result[1];&lt;br /&gt;
}&lt;br /&gt;
else {&lt;br /&gt;
  return invokeSynchronous(address, method, ...);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
} def invoke(address, method, ...) {&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;if (isDirect(address, method)) {&lt;br /&gt;
  return invokeDirect(address, method, ...);&lt;br /&gt;
}&lt;br /&gt;
else {&lt;br /&gt;
  return invokeSynchronous(address, method, ...);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
} ```&lt;br /&gt;
&lt;br /&gt;
== 注册架构 ==&lt;br /&gt;
&lt;br /&gt;
这一步非常简单，只需调用`li.cil.oc.api.Machine.add(PseudoArchitecture.class)`即可。注册架构后CPU即可提供被注册的架构。如果你不想让OC模组的CPU提供你的架构，那么你可以添加自己的`Processor`驱动程序以用于访问架构。或者更进一步，添加你自己的电脑方块，专用于运行你的架构。&lt;br /&gt;
&lt;br /&gt;
== 目录 ==&lt;br /&gt;
&lt;br /&gt;
{{:Tutorial/contents/zh}}&lt;br /&gt;
&lt;/div&gt;</summary>
		<author><name>imported&gt;OCDoc Import</name></author>
	</entry>
</feed>