Differences

This shows you the differences between two versions of the page.

Link to this comparison view

Both sides previous revision Previous revision
Next revision
Previous revision
tutorial:modding_architecture:zh [2023/11/03 06:27]
hfsr [使用架构]
tutorial:modding_architecture:zh [2023/11/03 08:00] (current)
hfsr [Example code]
Line 6: Line 6:
 架构是什么? 架构是什么?
 ----------------------- -----------------------
-首先让我们来申明OC模组语境下的“架构”是什么。架构指将某种代码执行器(以下称VM,虚拟机)和OC模组的组件/​Minecraft结合起来的程序。OC将组件逻辑与电脑逻辑严格分开。换言之,组件(例如显卡)不知道它自身在使用什么架构。反过来,架构也不知道组件如何工作。传递的一切信息都由**执行机**处理。执行机驱动架构,并提供回调函数使架构能与外界通信。+首先让我们来申明OC模组语境下的“架构”是什么。架构指将某种代码执行器(以下称虚拟机)和OC模组的组件/​Minecraft结合起来的程序。OC将组件逻辑与电脑逻辑严格分开。换言之,组件(例如显卡)不知道它自身在使用什么架构。反过来,架构也不知道组件如何工作。传递的一切信息都由**执行机**处理。执行机驱动架构,并提供回调函数使架构能与外界通信。
  
 使用架构 使用架构
Line 22: Line 22:
 - 执行机被创建时,架构即被创建。 - 执行机被创建时,架构即被创建。
 - 执行机启动或重启时,会要求`initialize()`自身。通常来说代表着创建底层虚拟机。 - 执行机启动或重启时,会要求`initialize()`自身。通常来说代表着创建底层虚拟机。
-- 驱动架构的标准方法是通过`runThreaded()`函数,它由执行器线程调用。架构的状态应在此处处理。其返回值类型被执行环境用于调度。**注意:**此方法不应抛出异常。你有责任处理所有错误,并在需要的时候将它们转换为代表报错的返回值。 ​+- 驱动架构的标准方法是通过`runThreaded()`函数,它由执行器线程调用。架构的状态应在此处处理。其返回值类型被执行用于调度。**注意:**此方法不应抛出异常。你有责任处理所有错误,并在需要的时候将它们转换为代表报错的返回值。 ​
 - 需要有一个特殊执行结果来表示进行“同步调用”。这个返回值会告诉执行机下次需要用`runSynchronized()`来驱动架构。这种调用**一定会由MC服务端线程执行**,代表着可以安全地在此回调函数中与世界交互。 - 需要有一个特殊执行结果来表示进行“同步调用”。这个返回值会告诉执行机下次需要用`runSynchronized()`来驱动架构。这种调用**一定会由MC服务端线程执行**,代表着可以安全地在此回调函数中与世界交互。
 - 执行机停止时会调用`close()`函数。然后释放所有打开的资源。 - 执行机停止时会调用`close()`函数。然后释放所有打开的资源。
  
-Providing context+提供上下文
 ----------------- -----------------
-In the most simple case, you just call some '​run'​ method in your VM each time `runThreaded()` ​is called. This is pretty useless, though, since you'll want to communicate with the outside somehow. For this, communication with components has to be provided to the VM. It is your responsibility to define the APIs inside the VM that are used to communicate with the machine'​s ​API (e.g. `components()` ​and `invoke()`).+在最简单的样例中,每次调用`runThreaded()`时在你的虚拟机中仅仅进行若干`run`调用。不过这样做实际用处不大,因为你会想要以某种方式与外界通信。为了实现此功能,需要将与组件的通信提供给虚拟机。你需要在虚拟机内定义用于与执行机API通信的API(例如:`components()``invoke()`)。
  
-Synchronized calls and call limits+同步调用与调用上限
 ---------------------------------- ----------------------------------
-Callbacks on components may declare to be "​direct",​ and in addition to that they may declare a "call limit"​. Per default, all component callbacks are *synchronizedcalls, i.e. the architecture must ensure that they are only called from runSynchronized(). +组件可能有一些回调函数声明为“直接调用”,此外它们可能还会定义“调用上限”。默认情况下,所有的组件回调函数都是**同步调用**,即架构必须保证这些函数只能由`runSynchronized()`调用。 
-The call limit for direct calls limits how often per tick any single method may be called from any single machine. The limit itself is enforced in the machine'​s ​invoke ​method, which will throw a `LimitReachedException` ​once there were too many call. At that point the architecture should either perform a short sleep, or fall back to perform a synchronized call instead.+直接调用的调用上限限制了单个执行机每tick调用某一个函数的次数。限制本身由执行机的`invoke`方法确保实现,此方法会在调用次数过多时抛出`LimitReachedException`异常。此时架构应当短暂休眠,或者改为执行非同步调用。
  
-- *Note*: while writing this I realized I forgot to pull some methods required to perform checks on this into the API. This will be remedied in the next API update, making methods for this available in the Component ​interface. For now, either reflect into it or build against the OC sources. Sorry about that.+- **注意:**在写这段内容的时候,我发现我忘记了把一些执行检查所需的方法放入API中。这将在下一个API更新中得到修复,使这些方法在`Component`接口中可用。现在的话,要么将它们反射进去,要么从OC源码自行构建模组。我对此表示抱歉。
  
-Example code+样例代码
 ------------ ------------
-Let's say you have some VM that provides the following interfaces:+假设你有能提供以下接口的虚拟机:
  
 ```java ```java
-/** The VM itself. This is just an example, it's not a "​real"​ interface. ​*/+/**虚拟机自身。这里的仅为一个样例,不是“真的”接口。*/
 public interface PseudoVM { public interface PseudoVM {
   Object[] run(Object[] args) throws Exception;   Object[] run(Object[] args) throws Exception;
Line 49: Line 49:
 } }
  
-/** Interface defining callbacks provided by the host. */+/**定义了主机提供的回调的接口。*/
 public interface PseudoNativeFunction { public interface PseudoNativeFunction {
   Object invoke(Object[] args);   Object invoke(Object[] args);
Line 55: Line 55:
 ``` ```
  
-A very primitive architecture implementation might look something like this:+一个简单的架构实现大概看起来像这样子:
  
 ```java ```java
-/** This is the class you implement; Architecture is from the OC API*/+/**这是你实现的类;这里的架构来自OCAPI*/
 @Architecture.Name("​Pseudolang"​) @Architecture.Name("​Pseudolang"​)
 public class PseudoArchitecture implements Architecture { public class PseudoArchitecture implements Architecture {
Line 65: Line 65:
   private PseudoVM vm;   private PseudoVM vm;
  
-  /** The constructor must have exactly this signature. ​*/+  /**构造函数的签名必须与此处完全一致。*/
   public PseudoArchitecture(Machine machine) {   public PseudoArchitecture(Machine machine) {
     this.machine = machine;     this.machine = machine;
Line 75: Line 75:
  
   public boolean initialize() {   public boolean initialize() {
-    // Set up new VM here, and register all API callbacks you want to +    //在此处新建虚拟机,并在里面注册你想要的所有API回调函数。
-    // provide to it.+
     vm = new PseudoVM();     vm = new PseudoVM();
     vm.setApiFunction("​invoke",​ new PseudoNativeFunction() {     vm.setApiFunction("​invoke",​ new PseudoNativeFunction() {
Line 87: Line 86:
         }         }
         catch (e LimitReachedException) {         catch (e LimitReachedException) {
-          // Perform logic also used to sleep perform synchronized calls. +          //这里的执行逻辑也可用于休眠/执行同步调用。 
-          // In this example we'll follow a protocol where if this returns +          //在此样例中我们遵循这样的协议: 
-          // (true, ​somethingthe call succeeded, if it returns ​(false) +          //成功时返回(true,某物),到达上限时返回(false) 
-          // the limit was reached. +          //此后虚拟机中运行的脚本需要将控制权交还给 
-          // The script running in the VM is then supposed to return control +          //初始化了当前执行的任务的调用者(例如,若支持的话 
-          // to the caller initiating the current execution (e.g. by yielding +          //可以yield,或者在事件驱动的系统中直接return)
-          // if supported, or just returning, when in an event driven system).+
           return new Object[]{false};​           return new Object[]{false};​
         }         }
Line 115: Line 113:
       }       }
     });     });
-    // ... more callbacks.+    // ... 更多回调。
     return true;     return true;
   }   }
Line 124: Line 122:
  
   ExecutionResult runThreaded(boolean isSynchronizedReturn) {   ExecutionResult runThreaded(boolean isSynchronizedReturn) {
-    // Perform stepping in here. Usually you'll want to resume the VM +    //在此处执行所需步骤。通常你会希望通过将队列中下一个信号传递给 
-    // by passing it the next signal from the queue, but you may decide +    //虚拟机的方式来唤醒它,但你也可能会选择让你的虚拟机手动拉取信号。
-    // to allow your VM to poll for signals manually.+
     try {     try {
       final Signal signal;       final Signal signal;
       if (isSynchronizedReturn) {       if (isSynchronizedReturn) {
-        // Don't pull signals when we're coming back from a sync call, +        //正在从同步调用中返回时不要拉取信号!因为我们正在执行其他事情。
-        // since we're in the middle of something else!+
         signal = null;         signal = null;
       }       }
Line 145: Line 141:
       }       }
  
-      // You'll want to define some internal protocol by which to decide +      //你可能会想定义一些内部协议,用以决定何时执行同步调用。 
-      // when to perform a synchronized call. Let's say we expect the VM +      //假设我们希望虚拟机在出现待决定的同步调用时返回数字值,代表休眠 
-      // to return either a number for a sleep, a boolean to indicate +      //或者返回布尔值,代表关机/重启或其他东西。
-      // shutdown/reboot and anything else a pending synchronous call.+
       if (result != null) {       if (result != null) {
         if (result[0] instanceof Boolean) {         if (result[0] instanceof Boolean) {
Line 157: Line 152:
         }         }
       }       }
-      // If this is returned, the next '​resume' ​will be runSynchronized. +      //若返回此值,下次'​resume'​时会调用runSynchronized 
-      // The next call to runThreaded ​after that call will have the +      //此次调用后的下次对runThreaded函数的调用中 
-      // isSynchronizedReturn ​argument set to true.+      //​isSynchronizedReturn参数将会设定为true
       return new ExecutionResult.SynchronizedCall();​       return new ExecutionResult.SynchronizedCall();​
     }     }
Line 168: Line 163:
  
   void runSynchronized() {   void runSynchronized() {
-    // Synchronized calls are run from the MC server thread, making it +    //同步调用在MC的服务端线程中执行,让回调与世界交互更方便 
-    // easier for callbacks to interact with the world (because sync is +    //(因为它们之间的同步由执行机/架构完成) 
-    // taken care for them by the machine ​architecture). +    //这意味着若虚拟机中的代码开始了一次同步调用,就需要*暂停
-    // This means that if some code in the VM starts a sync call it has +    //并且放弃对主机的控制,然后我们切换到同步调用模式(参看runThreaded), 
-    // to *pauseand relinquish control to the host, where we then +    //并等待MC服务端线程,接着再进行实际的调用。 
-    // switch to sync call mode (see runThreaded), wait for the MC server +    //可以在runThread中传递调用所需的信息,将其存储在架构中, 
-    // thread, and then do the actual call. It'd be possible to pass the +    //然后在此处直接进行调用。 
-    // info required for the call out in runThreaded,​ keep it around in +    //对此样例而言,让我们假定状态信息存储于虚拟机内部,并且 
-    // the arch and do the call directly here. For this example, let's +    //下次resume使其进行*实际*调用。下面给出了处理它们的伪代码。
-    // assume the state info is kept inside the VM, and the next resume +
-    // makes it perform the *actualcall. For some pseudo-code handling +
-    // this in the VM, see below.+
     vm.run(null);​     vm.run(null);​
   }   }
Line 185: Line 177:
   void onConnect() {}   void onConnect() {}
  
-  // Use this to load the VM state, if it can be persisted.+  //用这行代码加载虚拟机状态,假如虚拟机可持续。
   void load(NBTTagCompound nbt) {}   void load(NBTTagCompound nbt) {}
  
-  // Use this to save the VM state, if it can be persisted.+  //用这行代码保存虚拟机状态,假如虚拟机可持续。
   void save(NBTTagCompound nbt) {}   void save(NBTTagCompound nbt) {}
 } }
 ``` ```
  
-Some pseudo-code for handling synchronized calls in the VM:+一些用于在虚拟机中处理同步调用的伪代码:
  
 ```scala ```scala
 private def invokeSynchronous(address,​ method, ...) { private def invokeSynchronous(address,​ method, ...) {
-  yield; // This is where it returns to runThreaded(). +  yield; //此处为返回到runThreaded()的地方。 
-   // ​This is where we enter in runSynchronized();​+   //此处为进入runSynchronized();​的地方
   val result = native.invoke(address,​ method, ...);   val result = native.invoke(address,​ method, ...);
-  // See definition of invoke in initialize() ​for values of result. +  //查看initialize()中invoke的定义以获取结果值的信息。 
-  yield; // And return to runSynchronized();​ +  yield; //并返回runSynchronized();​ 
-  // And the next runThreaded() ​enters again.+  //并且下一个runThreaded()又进入了。
   return result[1];   return result[1];
 } }
 private def invokeDirect(address,​ method, ...) { private def invokeDirect(address,​ method, ...) {
   val result = native.invoke(address,​ method, ...);   val result = native.invoke(address,​ method, ...);
-  // See definition of invoke in initialize() ​for values of result.+  //查看initialize()中invoke的定义以获取结果值的信息。
   if (result[0] == true) {   if (result[0] == true) {
     return result[1];     return result[1];
Line 225: Line 217:
 ``` ```
  
-Registering an architecture+注册架构
 --------------------------- ---------------------------
-This one's pretty simple: just do `li.cil.oc.api.Machine.add(PseudoArchitecture.class)`. This will allow CPUs to provide the registered architecture. If you do not wish OC CPUs to provide your architecture,​ you can either add your own `Processor` ​driver that can be used to get access to the architecture,​ or go one step further and add your own computer block, that will exclusively run your architecture,​ for example.+这一步非常简单,只需调用`li.cil.oc.api.Machine.add(PseudoArchitecture.class)`即可。注册架构后CPU即可提供被注册的架构。如果你不想让OC模组的CPU提供你的架构,那么你可以添加自己的`Processor`驱动程序以用于访问架构。或者更进一步,添加你自己的电脑方块,专用于运行你的架构。
  
 目录 目录
 ------------ ------------
 {{page>​tutorial:​contents:​zh&​noheader&​noeditbutton&​nouser&​nofooter}} {{page>​tutorial:​contents:​zh&​noheader&​noeditbutton&​nouser&​nofooter}}