Compare commits
14
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
412158bad5 | ||
|
|
419cec369a | ||
|
|
4399ce1523 | ||
|
|
770cdec7f9 | ||
|
|
b51852c15b | ||
|
|
9c7845580b | ||
|
|
3b4bc76cc6 | ||
|
|
579c7064e2 | ||
|
|
0ae97629e3 | ||
|
|
206d7579ae | ||
|
|
34f98ad930 | ||
|
|
a0e3d1751f | ||
|
|
726fef01f6 | ||
|
|
f523d73954 |
No files matched your search
@@ -2,6 +2,11 @@ name: Build
|
|||||||
|
|
||||||
on:
|
on:
|
||||||
push:
|
push:
|
||||||
|
paths-ignore:
|
||||||
|
- '**.md'
|
||||||
|
- 'reports/**'
|
||||||
|
- '.github/ISSUE_TEMPLATE/**'
|
||||||
|
- '.gitignore'
|
||||||
pull_request:
|
pull_request:
|
||||||
workflow_dispatch:
|
workflow_dispatch:
|
||||||
inputs:
|
inputs:
|
||||||
|
|||||||
@@ -1,22 +0,0 @@
|
|||||||
# F-001
|
|
||||||
- **状态**:修·已修复(会话合入 TDLM/thaumicadditions#4,2026-10-26)
|
|
||||||
- **范式**:B1
|
|
||||||
- **位置**:`.github/workflows/build.yml:3-5`、`:55`
|
|
||||||
- **证据**:
|
|
||||||
```yaml
|
|
||||||
on:
|
|
||||||
push:
|
|
||||||
branches: [main]
|
|
||||||
```
|
|
||||||
(`.github/workflows/build.yml:3-5`;全文件无 `concurrency:` 键)
|
|
||||||
```yaml
|
|
||||||
if: ${{ github.event_name == 'push' || inputs.publish == 'true' }}
|
|
||||||
```
|
|
||||||
(`:55`;`:24`/`:57` `timeout-minutes` 在位)
|
|
||||||
- **机制**:workflow 无 concurrency 组而 push 即进入 publish job,连续 push 并行构建并争发构件。
|
|
||||||
- **频率**:每次 push(CI 期)。
|
|
||||||
- **修法**:补 `concurrency: { group: ${{ github.workflow }}-${{ github.ref }}, cancel-in-progress: false }`(含发布步骤,取 false 保逐 commit 构件)。
|
|
||||||
- **风险 · 置信度**:无(仅消并发发布竞争) · 高
|
|
||||||
- **移交**:无
|
|
||||||
- **来源**:P1 2026-10-26 2f7b9c9
|
|
||||||
- **修复**:会话合入 TDLM/thaumicadditions#4,2026-10-26。
|
|
||||||
@@ -1,19 +0,0 @@
|
|||||||
# F-002
|
|
||||||
- **状态**:修·已修复(会话合入 TDLM/thaumicadditions#4,2026-10-26)
|
|
||||||
- **范式**:B1
|
|
||||||
- **位置**:`build.gradle:19-28`
|
|
||||||
- **证据**:
|
|
||||||
```gradle
|
|
||||||
repositories {
|
|
||||||
maven {
|
|
||||||
name = 'TDLM Maven'
|
|
||||||
url = 'https://git.nest.potatolab.uk:8443/api/packages/TDLM/maven'
|
|
||||||
```
|
|
||||||
(`build.gradle:18-21`;块内无 `content { includeGroup … }`;对照 `settings.gradle:6-8` GTNH 块有 mavenContent 正例)
|
|
||||||
- **机制**:自建 TDLM maven 无 content 过滤,依赖解析对无关坐标反复探测 404。
|
|
||||||
- **频率**:每次依赖解析(构建期)。
|
|
||||||
- **修法**:maven 块补 `content { includeGroup("uk.potatolab") }`(或本仓实际 group 集合)。
|
|
||||||
- **风险 · 置信度**:无 · 高
|
|
||||||
- **移交**:无
|
|
||||||
- **来源**:P1 2026-10-26 2f7b9c9
|
|
||||||
- **修复**:会话合入 TDLM/thaumicadditions#4,2026-10-26。
|
|
||||||
@@ -1,16 +0,0 @@
|
|||||||
# F-003
|
|
||||||
- **状态**:修·已修复(会话合入 TDLM/thaumicadditions#4,2026-10-26)
|
|
||||||
- **范式**:T4
|
|
||||||
- **位置**:`src/main/java/com/pengu/thaumcraft/additions/tileentity/TileVoidChest.java:55`
|
|
||||||
- **证据**:
|
|
||||||
```java
|
|
||||||
public void updateEntity() {}
|
|
||||||
```
|
|
||||||
(`:55`;全仓 `boolean canUpdate(` 覆写 0;1.7.10 `TileEntity.canUpdate()` 默认 true;注册见 `init/MTE.java:37`)
|
|
||||||
- **机制**:虚空箱有空体 updateEntity 且未关 tick 资格,世界内每箱每 tick 白付调度。
|
|
||||||
- **频率**:每 tick × 每虚空箱实例。
|
|
||||||
- **修法**:覆写 `canUpdate()` 返回 false(空体无副作用,零行为变更)。
|
|
||||||
- **风险 · 置信度**:无 · 高
|
|
||||||
- **移交**:无
|
|
||||||
- **来源**:P1 2026-10-26 2f7b9c9;同族 F-004
|
|
||||||
- **修复**:会话合入 TDLM/thaumicadditions#4,2026-10-26。
|
|
||||||
@@ -1,16 +0,0 @@
|
|||||||
# F-004
|
|
||||||
- **状态**:修·已修复(会话合入 TDLM/thaumicadditions#4,2026-10-26)
|
|
||||||
- **范式**:T4
|
|
||||||
- **位置**:`src/main/java/com/pengu/thaumcraft/additions/tileentity/TileReturner.java:6`
|
|
||||||
- **证据**:
|
|
||||||
```java
|
|
||||||
public class TileReturner extends TileEntity {
|
|
||||||
```
|
|
||||||
(`:6`;类内无 `updateEntity`/`canUpdate`;`BlockReturner.java:22` `TileEntity.addMapping(TileReturner.class, …)`)
|
|
||||||
- **机制**:返回器仅存坐标 NBT,继承基类空 updateEntity,默认 canUpdate=true 仍进 tick 表。
|
|
||||||
- **频率**:每 tick × 每返回器。
|
|
||||||
- **修法**:覆写 `canUpdate()` 返回 false。
|
|
||||||
- **风险 · 置信度**:无 · 高
|
|
||||||
- **移交**:无
|
|
||||||
- **来源**:P1 2026-10-26 2f7b9c9;同族 F-003
|
|
||||||
- **修复**:会话合入 TDLM/thaumicadditions#4,2026-10-26。
|
|
||||||
@@ -1,19 +0,0 @@
|
|||||||
# F-005
|
|
||||||
- **状态**:观察·已修复(TDLM/thaumicadditions#11,2026-10-31:TESR 模型与贴图改为字段/静态常量,不再每帧新建模型(顺带消除每帧新编译显示列表))
|
|
||||||
- **范式**:F1
|
|
||||||
- **位置**:`src/main/java/com/pengu/thaumcraft/additions/renderer/RendererDarkGen.java:16`、`:22`;同型 `RendererHyperNodeCreator.java:17`、`:23`、`RendererInfuser.java:19`、`:24`、`RendererInfuserActivator.java:19`、`:37`、`RendererSymboller.java:17`、`:23`、`RendererThaumicGenerator.java:17`、`:23`、`RendererThaumicRestorer.java:16`、`:22`、`RendererSeal.java:41-48`、`RendererTankBasic.java:20`、`:32`、`TileRendererCreativeNode.java:22`、`:23`、`:34`(后者每帧 `new Random`/`Calendar.getInstance()`/RL 字符串拼接)
|
|
||||||
- **证据**:
|
|
||||||
```java
|
|
||||||
ResourceLocation textures = new ResourceLocation("thaumicadditions", "textures/models/DarkGen.png");
|
|
||||||
```
|
|
||||||
(RendererDarkGen.java:16)
|
|
||||||
```java
|
|
||||||
(new ModelDarkGen()).render((Entity)null, 0.0F, 0.0F, -0.1F, 0.0F, 0.0F, 0.0625F, false);
|
|
||||||
```
|
|
||||||
(`:22`;Seal 同帧多次 `new ModelSeal()` 见 RendererSeal.java:42/:48/:61/:72/:83)
|
|
||||||
- **机制**:多枚 TESR 每帧重建不可变 ResourceLocation 与 Model 实例;路径常量可 static final,Model 可字段复用。
|
|
||||||
- **频率**:每帧 × 可视 TESR 实例。
|
|
||||||
- **修法**:提 `private static final ResourceLocation`;Model 提实例字段复用(需确认无跨 TE 可变状态串扰,故本档观察)。
|
|
||||||
- **风险 · 置信度**:RL 提常量无;Model 复用需隔离论证 · 高(形态)
|
|
||||||
- **移交**:无
|
|
||||||
- **来源**:P1 2026-10-26 2f7b9c9;P2 2026-10-29 c49b5f0 同型补记 `TileRendererCreativeNode.java:22`、`:23`、`:34`(计数不变);同族 F-006/F-016
|
|
||||||
@@ -1,20 +0,0 @@
|
|||||||
# F-006
|
|
||||||
- **状态**:观察·已修复(TDLM/thaumicadditions#11,2026-10-31:Random 复用并 setSeed(序列不变),光环贴图预建,毫秒取 currentTimeMillis%1000)
|
|
||||||
- **范式**:F1
|
|
||||||
- **位置**:`src/main/java/com/pengu/thaumcraft/additions/tileentity/TileRendererCreativeNode.java:22-23`、`:34`
|
|
||||||
- **证据**:
|
|
||||||
```java
|
|
||||||
Random rnd = new Random((long)(tcn.getId() + "" + tcn.yCoord).hashCode() ^ 256L);
|
|
||||||
float rot = (float)(Calendar.getInstance().get(14) + rnd.nextInt(1000)) % 1000.0F;
|
|
||||||
```
|
|
||||||
(`:22-23`)
|
|
||||||
```java
|
|
||||||
Minecraft.getMinecraft().getTextureManager().bindTexture(new ResourceLocation("thaumicadditions", "textures/models/aura_" + (rnd.nextInt(2) + 1) + ".png"));
|
|
||||||
```
|
|
||||||
(`:34`)
|
|
||||||
- **机制**:创造节点 TESR 每帧 new Random、Calendar.getInstance、拼接 ResourceLocation;固定种子序列可预计算。
|
|
||||||
- **频率**:每帧 × 可视创造节点。
|
|
||||||
- **修法**:种子 Random/两张 aura RL 提字段;时间改 `System.currentTimeMillis()%1000` 或字段时钟。量级未证 ⇒ 观察。
|
|
||||||
- **风险 · 置信度**:低(动画相位需对齐) · 高(形态)
|
|
||||||
- **移交**:无
|
|
||||||
- **来源**:P1 2026-10-26 2f7b9c9;同族 F-005
|
|
||||||
@@ -1,18 +0,0 @@
|
|||||||
# F-007
|
|
||||||
- **状态**:观察·已驳回(TDLM/thaumicadditions#11,2026-10-31:每趟内爆炸会生成新奇点并改动实体,且每趟破坏随机方块,提出查询会改变吸取结果)
|
|
||||||
- **范式**:S1
|
|
||||||
- **位置**:`src/main/java/com/pengu/thaumcraft/additions/entity/EntitySingularity.java:70-73`
|
|
||||||
- **证据**:
|
|
||||||
```java
|
|
||||||
for(p = 0; p < 128; ++p) {
|
|
||||||
AxisAlignedBB ent = AxisAlignedBB.getBoundingBox(this.posX - (double)this.radius, this.posY - (double)this.radius, this.posZ - (double)this.radius, this.posX + (double)this.radius, this.posY + (double)this.radius, this.posZ + (double)this.radius);
|
|
||||||
l = this.worldObj.getEntitiesWithinAABB(Entity.class, ent);
|
|
||||||
l2 = this.worldObj.getEntitiesWithinAABB(EntityLivingBase.class, ent);
|
|
||||||
```
|
|
||||||
(`:70-73`;`radius = 10` 见 `:22`;落地分支 `:56`)
|
|
||||||
- **机制**:奇点落地后每 tick 将同一 21³ 盒 AABB 查询重复 128 次×两类实体,盒有界但频率无 interval,乘子为设计放大。
|
|
||||||
- **频率**:每 tick × 每落地奇点 × 256 次查询(静态推断)。
|
|
||||||
- **修法**:单次双查询后在循环内处理;或降循环次数。行为/手感可能变 ⇒ 观察,量级需 profile。
|
|
||||||
- **风险 · 置信度**:中(牵引力/破坏节奏) · 高(形态)
|
|
||||||
- **移交**:无
|
|
||||||
- **来源**:P1 2026-10-26 2f7b9c9
|
|
||||||
@@ -1,16 +0,0 @@
|
|||||||
# F-008
|
|
||||||
- **状态**:观察·已驳回(TDLM/thaumicadditions#11,2026-10-31:加间隔会改变拾取时机)
|
|
||||||
- **范式**:S1
|
|
||||||
- **位置**:`src/main/java/com/pengu/thaumcraft/additions/event/sealing/SealEventCollectItems.java:25-26`
|
|
||||||
- **证据**:
|
|
||||||
```java
|
|
||||||
AxisAlignedBB aabb = AxisAlignedBB.getBoundingBox((double)(x - 16), (double)(y - 16), (double)(z - 16), (double)(x + 16), (double)(y + 16), (double)(z + 16));
|
|
||||||
List i = world.getEntitiesWithinAABB(EntityItem.class, aabb);
|
|
||||||
```
|
|
||||||
(`:25-26`;由 `TileSeal.updateEntity` `:62` 每 tick 调用)
|
|
||||||
- **机制**:收集印激活时每 tick 扫 33³ 盒掉落物,有半径无 interval/短路门。
|
|
||||||
- **频率**:每 tick × 每匹配收集印。
|
|
||||||
- **修法**:加 interval 或相位门;缩小盒需平衡裁决。量级未证 ⇒ 观察。
|
|
||||||
- **风险 · 置信度**:中(收集半径即玩法) · 高(形态)
|
|
||||||
- **移交**:无
|
|
||||||
- **来源**:P1 2026-10-26 2f7b9c9
|
|
||||||
@@ -1,19 +0,0 @@
|
|||||||
# F-009
|
|
||||||
- **状态**:观察·已驳回(TDLM/thaumicadditions#11,2026-10-31:配方缓存需槽位变更失效,反编译 TE 无干净钩子)
|
|
||||||
- **范式**:T1
|
|
||||||
- **位置**:`src/main/java/com/pengu/thaumcraft/additions/tileentity/TileInfuser.java:41-45`;`TileDarkInfuser.java:41-45`
|
|
||||||
- **证据**:
|
|
||||||
```java
|
|
||||||
List var5 = InfuserRecipeRegistry.complexOfRecipes.recipesOnTheRegularInfuser;
|
|
||||||
int foundRecipes = 0;
|
|
||||||
|
|
||||||
for(int i = 0; i < var5.size(); ++i) {
|
|
||||||
if(areItemStacksEqual(this.slots[1], ((InfuserRecipe)var5.get(i)).input1) && areItemStacksEqual(this.slots[2], ((InfuserRecipe)var5.get(i)).input2) && areItemStacksEqual(this.slots[3], ((InfuserRecipe)var5.get(i)).input3) && areItemStacksEqual(this.slots[4], ((InfuserRecipe)var5.get(i)).input4) && areItemStacksEqual(this.slots[5], ((InfuserRecipe)var5.get(i)).input5) && areItemStacksEqual(this.slots[6], ((InfuserRecipe)var5.get(i)).input6) && (this.slots[0] == null || areItemStacksEqual(this.slots[0], ((InfuserRecipe)var5.get(i)).output) && this.slots[0].stackSize + ((InfuserRecipe)var5.get(i)).output.stackSize < this.slots[0].getMaxStackSize())) {
|
|
||||||
```
|
|
||||||
(TileInfuser.java:41-45;Dark 表同型 `:41-45`;注册约 7+4 条见 `init/MIR.java`)
|
|
||||||
- **机制**:注能/暗注能每 tick 无缓存全表线性匹配六格输入;表近静态。
|
|
||||||
- **频率**:每 tick × 每台注能器。
|
|
||||||
- **修法**:槽位指纹缓存命中配方下标,槽变更失效。表小量级未证 ⇒ 观察。
|
|
||||||
- **风险 · 置信度**:低 · 高(形态)
|
|
||||||
- **移交**:无
|
|
||||||
- **来源**:P1 2026-10-26 2f7b9c9
|
|
||||||
@@ -1,15 +0,0 @@
|
|||||||
# F-010
|
|
||||||
- **状态**:观察·已修复(TDLM/thaumicadditions#11,2026-10-31:每向邻居 TE 只取一次)
|
|
||||||
- **范式**:T1
|
|
||||||
- **位置**:`src/main/java/com/pengu/thaumcraft/additions/tileentity/TileTileBooster.java:27`
|
|
||||||
- **证据**:
|
|
||||||
```java
|
|
||||||
TileEntity te = this.worldObj.getTileEntity(x, y, z) != null && !(this.worldObj.getTileEntity(x, y, z) instanceof TileTileBooster)?this.worldObj.getTileEntity(x, y, z):null;
|
|
||||||
```
|
|
||||||
(`:27`;六向循环 `:22-33`)
|
|
||||||
- **机制**:加速器每 tick 每向对同坐标最多三次 getTileEntity。
|
|
||||||
- **频率**:每 tick × 6 向 × 每加速器。
|
|
||||||
- **修法**:`TileEntity te = worldObj.getTileEntity(x,y,z)` 提局部一次。零行为;量级随实例未证 ⇒ 观察。
|
|
||||||
- **风险 · 置信度**:无 · 高
|
|
||||||
- **移交**:无
|
|
||||||
- **来源**:P1 2026-10-26 2f7b9c9;同族 F-011/F-013
|
|
||||||
@@ -1,15 +0,0 @@
|
|||||||
# F-011
|
|
||||||
- **状态**:观察·已修复(TDLM/thaumicadditions#11,2026-10-31:每向 TE 取一次;isModLoaded 静态常量;Botania 桥接单例;方向数组静态)
|
|
||||||
- **范式**:T1
|
|
||||||
- **位置**:`src/main/java/com/pengu/thaumcraft/additions/tileentity/TileThaumicGenerator.java:62-87`、`:71`
|
|
||||||
- **证据**:
|
|
||||||
```java
|
|
||||||
if(Loader.isModLoaded("Botania") && (new Botania()).canConnect(this.worldObj, this.xCoord, this.yCoord, this.zCoord, dirs[i])) {
|
|
||||||
```
|
|
||||||
(`:71`;同方法 `:62-82` 多处重复 `getTileEntity(...)`;`:85-86` 再次 `Loader.isModLoaded` + `new Botania()`)
|
|
||||||
- **机制**:发电机有能量时每 tick 六向重复 TE 查找,并反复 `Loader.isModLoaded` 与 `new Botania()`。
|
|
||||||
- **频率**:每 tick × 有能量的发电机 × 6 向。
|
|
||||||
- **修法**:`isModLoaded` 提 static final;Botania 桥接单例;getTileEntity 提局部。量级未证 ⇒ 观察。
|
|
||||||
- **风险 · 置信度**:低 · 高(形态)
|
|
||||||
- **移交**:无
|
|
||||||
- **来源**:P1 2026-10-26 2f7b9c9;同族 F-010
|
|
||||||
@@ -1,24 +0,0 @@
|
|||||||
# F-012
|
|
||||||
- **状态**:观察·已驳回(TDLM/thaumicadditions#11,2026-10-31:印面组合缓存需印面变更失效,语义难核)
|
|
||||||
- **范式**:T1
|
|
||||||
- **位置**:`src/main/java/com/pengu/thaumcraft/additions/tileentity/TileSeal.java:43`、`:57-62`
|
|
||||||
- **证据**:
|
|
||||||
```java
|
|
||||||
this.current = new SealCombo(new Seal[]{this.f});
|
|
||||||
```
|
|
||||||
(`:43`)
|
|
||||||
```java
|
|
||||||
List events = MSE.events.eventList;
|
|
||||||
|
|
||||||
for(int i = 0; i < events.size(); ++i) {
|
|
||||||
if(this.CompareSealCombos(this.f, ((SealEvent)events.get(i)).getSealCombination().getSeal1()) && this.CompareSealCombos(this.s, ((SealEvent)events.get(i)).getSealCombination().getSeal2()) && this.CompareSealCombos(this.t, ((SealEvent)events.get(i)).getSealCombination().getSeal3()) || this.current.length() == 3 && ((SealEvent)events.get(i)).getSealCombination().length() == 2 && ((SealEvent)events.get(i)).canWorkWith3rdSymbol(this.t)) {
|
|
||||||
SealEvent event = (SealEvent)events.get(i);
|
|
||||||
event.sealTick(this.worldObj, this.xCoord, this.yCoord, this.zCoord, this.f, this.s, this.t, this.extraNBT);
|
|
||||||
```
|
|
||||||
(`:57-62`)
|
|
||||||
- **机制**:封印每 tick 新建 SealCombo 并对近静态事件表线性匹配;印面未变时结果可记忆。
|
|
||||||
- **频率**:每 tick × 每封印方块。
|
|
||||||
- **修法**:印面指纹缓存 `currentWorkingComboID`,变更再全表扫。缓存语义需核对 ⇒ 观察。
|
|
||||||
- **风险 · 置信度**:低 · 中
|
|
||||||
- **移交**:无
|
|
||||||
- **来源**:P1 2026-10-26 2f7b9c9
|
|
||||||
@@ -1,16 +0,0 @@
|
|||||||
# F-013
|
|
||||||
- **状态**:观察·已修复(TDLM/thaumicadditions#11,2026-10-31:每向邻居 TE 只取一次)
|
|
||||||
- **范式**:T1
|
|
||||||
- **位置**:`src/main/java/com/pengu/thaumcraft/additions/piping/TileVisTube.java:61-75`、`:98`
|
|
||||||
- **证据**:
|
|
||||||
```java
|
|
||||||
if(this.worldObj.getTileEntity(x, y, z) instanceof ITubeConnectable) {
|
|
||||||
ITubeConnectable tube = (ITubeConnectable)this.worldObj.getTileEntity(x, y, z);
|
|
||||||
```
|
|
||||||
(`:61-62`;`:74-75` 同坐标再查 `ITubable`;`:98` 合并环再双查)
|
|
||||||
- **机制**:灵气管每 tick 六向对同坐标多次 getTileEntity 做连通与合并。
|
|
||||||
- **频率**:每 tick × 每管段 × 至多两轮六向。
|
|
||||||
- **修法**:每向 `TileEntity te = getTileEntity(...)` 一次后分支。零行为;管网密度未证 ⇒ 观察。
|
|
||||||
- **风险 · 置信度**:无 · 高
|
|
||||||
- **移交**:无
|
|
||||||
- **来源**:P1 2026-10-26 2f7b9c9;同族 F-010
|
|
||||||
@@ -1,19 +0,0 @@
|
|||||||
# F-014
|
|
||||||
- **状态**:边界·已修复(TDLM/thaumicadditions#11,2026-10-31:长度按包内剩余字节校验,超限解码失败)
|
|
||||||
- **范式**:N1
|
|
||||||
- **位置**:`src/main/java/com/pengu/thaumcraft/additions/playnet/packtetmng/PacketAuraVis.java:38`、`:45`
|
|
||||||
- **证据**:
|
|
||||||
```java
|
|
||||||
this.amts = new int[buf.readInt()];
|
|
||||||
```
|
|
||||||
(`:38`)
|
|
||||||
```java
|
|
||||||
this.aspects = new EnumAT[buf.readInt()];
|
|
||||||
```
|
|
||||||
(`:45`;分配后无 clamp)
|
|
||||||
- **机制**:两处数组长度直取网络 int,无上限;畸形包可驱动大分配。
|
|
||||||
- **频率**:每入站包。
|
|
||||||
- **修法**:记录不修(边界):协议本为短枚举列表;上限取值需安全侧/包维护者裁决。建议 clamp 至 `EnumAT` 基数后超限断连。
|
|
||||||
- **风险 · 置信度**:安全相邻 · 高(形态)
|
|
||||||
- **移交**:安全侧
|
|
||||||
- **来源**:P1 2026-10-26 2f7b9c9
|
|
||||||
@@ -1,15 +0,0 @@
|
|||||||
# F-015
|
|
||||||
- **状态**:边界·已驳回(TDLM/thaumicadditions#11,2026-10-31:预约爆炸会改变时序分布)
|
|
||||||
- **范式**:T15
|
|
||||||
- **位置**:`src/main/java/com/pengu/thaumcraft/additions/tileentity/TileTankBasic.java:45`
|
|
||||||
- **证据**:
|
|
||||||
```java
|
|
||||||
boolean ttb = rand.nextInt(1000) < 100 && ext > 0.5F;
|
|
||||||
```
|
|
||||||
(`:45`;`:43` `!isRemote` 门内每 tick)
|
|
||||||
- **机制**:污秽过半时每 tick 重掷约 10% 爆炸门,事件稀疏却抽样= tick×实例。
|
|
||||||
- **频率**:每 tick × 高污秽储罐。
|
|
||||||
- **修法**:记录不修:分布改倒计时会变爆炸时序;量级在污秽门后。若修则预约下次爆炸 tick。
|
|
||||||
- **风险 · 置信度**:中(时序) · 高(形态)
|
|
||||||
- **移交**:无
|
|
||||||
- **来源**:P1 2026-10-26 2f7b9c9
|
|
||||||
@@ -1,15 +0,0 @@
|
|||||||
# F-016
|
|
||||||
- **状态**:边界·已修复(TDLM/thaumicadditions#11,2026-10-31:十个 GUI 背景贴图 static final)
|
|
||||||
- **范式**:F1
|
|
||||||
- **位置**:`src/main/java/com/pengu/thaumcraft/additions/gui/GUIInfuser.java:24`;同型 `GUICondensator.java:26`、`GUIDarkGenerator.java:26`、`GUIDarkInfuser.java:26`、`GUIHyperNodeCreator.java:25`、`GUISealGlobe.java:38`、`GUIThaumicCrystallizer.java:24`、`GUIThaumicGenerator.java:24`、`GUIThaumicRestorer.java:25`、`GUIVoidChest.java:23`
|
|
||||||
- **证据**:
|
|
||||||
```java
|
|
||||||
Minecraft.getMinecraft().getTextureManager().bindTexture(new ResourceLocation("thaumicadditions", "textures/gui/guiinfuser.png"));
|
|
||||||
```
|
|
||||||
(GUIInfuser.java:24;其余 9 处同句式换路径)
|
|
||||||
- **机制**:十个容器 GUI 背景层每帧 new ResourceLocation;可提 static final。
|
|
||||||
- **频率**:每帧(GUI 打开期间)。
|
|
||||||
- **修法**:记录不修——量级算式:开窗期每帧 1 个 `ResourceLocation`(对象+两段字符串小写,约 0.2–0.5 µs)⇒ ≤0.003% 帧预算;若要收:提 `private static final ResourceLocation`,逐字节不变。
|
|
||||||
- **风险 · 置信度**:无 · 高
|
|
||||||
- **移交**:无
|
|
||||||
- **来源**:P1 2026-10-26 2f7b9c9;同族 F-005
|
|
||||||
@@ -1,15 +0,0 @@
|
|||||||
# F-017
|
|
||||||
- **状态**:观察·已修复(TDLM/thaumicadditions#11,2026-10-31:删除每包 INFO 日志)
|
|
||||||
- **范式**:D1
|
|
||||||
- **位置**:`src/main/java/com/pengu/thaumcraft/additions/playnet/packtetmng/PacketAuraVis.java:25`
|
|
||||||
- **证据**:
|
|
||||||
```java
|
|
||||||
FMLLog.info("Received!", new Object[0]);
|
|
||||||
```
|
|
||||||
(`:25`;`onMessage` 内、try 块首行)
|
|
||||||
- **机制**:灵气同步包每包打 INFO,控制台同步 IO 随包频放大。
|
|
||||||
- **频率**:每包(客户端收包沿)。
|
|
||||||
- **修法**:删除该行或改 `FMLLog.fine`/debug 开关。若运维依赖该日志则裁决。
|
|
||||||
- **风险 · 置信度**:低(可观测性) · 高
|
|
||||||
- **移交**:无
|
|
||||||
- **来源**:P1 2026-10-26 2f7b9c9;同点位 F-014
|
|
||||||
@@ -1,19 +0,0 @@
|
|||||||
# F-018
|
|
||||||
- **状态**:边界·已驳回(TDLM/thaumicadditions#11,2026-10-31:GUI 内测宽量级微,且脚本打不开这些 GUI 无法实测)
|
|
||||||
- **范式**:F13
|
|
||||||
- **位置**:`src/main/java/com/pengu/thaumcraft/additions/gui/GUIDarkGenerator.java:35`、`:36`;同型 `GUICondensator.java:39`、`GUIDarkInfuser.java:44`、`GUIHyperNodeCreator.java:31`、`:32`、`GUIInfuser.java:35`、`GUISealGlobe.java:76`、`GUIThaumicCrystallizer.java:34`、`GUIThaumicGenerator.java:32`、`GUIThaumicRestorer.java:33`;`src/main/java/com/pengu/thaumcraft/additions/utils/hud/TipMessage.java:35`(宽度环 `:69-81`,入口同包 `HUD.java:111`)
|
|
||||||
- **证据**:
|
|
||||||
```java
|
|
||||||
this.fontRendererObj.drawString(name, this.xSize / 2 - this.fontRendererObj.getStringWidth(name) / 2, 3, 4210752);
|
|
||||||
```
|
|
||||||
(GUIDarkGenerator.java:35;`:36` 对 `Lang.localiseRaw("container.inventory")` 取两次翻译再做同式居中)
|
|
||||||
```java
|
|
||||||
float decrease = this.getStringWidth(this.tipText) / 2.0F;
|
|
||||||
```
|
|
||||||
(TipMessage.java:35;`tipText` 为 final 字段 `:9`,宽度环 `:69-81` 逐字符 `loadGlyphTexture` → `renderEngine.bindTexture`)
|
|
||||||
- **机制**:9 个 `drawGuiContainerForegroundLayer` 与 HUD 提示每帧对不变串重测宽度、随即 `drawString` 内部再测一遍,偏移只用于居中。串与字体在开窗/提示存活期内不变(`GUISealGlobe.java:67`/`:70` 同帧重取 TE 与组合描述属另一面,本块不计)。
|
|
||||||
- **频率**:每帧(GUI 开启期)/每帧(提示存活期)。
|
|
||||||
- **修法**:记录不修——量级算式:GUI 侧 10–20 字符测宽约 100–300 ns,`GUIDarkGenerator:35-36` 另加两次 `localiseRaw`,`GUISealGlobe:76` 含每行翻译与测宽合计 ≤3 µs/帧(16.6 ms 的 ≤0.02%);HUD 侧 10–40 字符 × 每次 `bindTexture` 0.2–1 µs ⇒ 2–40 µs/帧(16.6 ms 的 ≤0.25%)且仅提示存活期间。若要收:开窗期把标题串与宽度缓存在 `initGui`/构造器,`TipMessage` 在构造器算好 `decrease`;宽度为定值,偏移逐像素不变。
|
|
||||||
- **风险 · 置信度**:无 · 高(形态)
|
|
||||||
- **移交**:无
|
|
||||||
- **来源**:P2 2026-10-29 c49b5f0
|
|
||||||
@@ -1,135 +0,0 @@
|
|||||||
# thaumicadditions — reports
|
|
||||||
|
|
||||||
本目录为该模组 F-item 的**权威来源**(自 TDLMPack `reports/repos/` 迁入)。
|
|
||||||
|
|
||||||
## 索引
|
|
||||||
|
|
||||||
| ID | 状态 | 文件 |
|
|
||||||
|---|---|---|
|
|
||||||
| [F-001](F-001.md) | 修·已修复 | `F-001.md` |
|
|
||||||
| [F-002](F-002.md) | 修·已修复 | `F-002.md` |
|
|
||||||
| [F-003](F-003.md) | 修·已修复 | `F-003.md` |
|
|
||||||
| [F-004](F-004.md) | 修·已修复 | `F-004.md` |
|
|
||||||
| [F-005](F-005.md) | 观察·已修复 | `F-005.md` |
|
|
||||||
| [F-006](F-006.md) | 观察·已修复 | `F-006.md` |
|
|
||||||
| [F-007](F-007.md) | 观察·已驳回 | `F-007.md` |
|
|
||||||
| [F-008](F-008.md) | 观察·已驳回 | `F-008.md` |
|
|
||||||
| [F-009](F-009.md) | 观察·已驳回 | `F-009.md` |
|
|
||||||
| [F-010](F-010.md) | 观察·已修复 | `F-010.md` |
|
|
||||||
| [F-011](F-011.md) | 观察·已修复 | `F-011.md` |
|
|
||||||
| [F-012](F-012.md) | 观察·已驳回 | `F-012.md` |
|
|
||||||
| [F-013](F-013.md) | 观察·已修复 | `F-013.md` |
|
|
||||||
| [F-014](F-014.md) | 边界·已修复 | `F-014.md` |
|
|
||||||
| [F-015](F-015.md) | 边界·已驳回 | `F-015.md` |
|
|
||||||
| [F-016](F-016.md) | 边界·已修复 | `F-016.md` |
|
|
||||||
| [F-017](F-017.md) | 观察·已修复 | `F-017.md` |
|
|
||||||
| [F-018](F-018.md) | 边界·已驳回 | `F-018.md` |
|
|
||||||
|
|
||||||
未关闭项(不含已修复/已延后):**6**(F-007, F-008, F-009, F-012, F-015, F-018)
|
|
||||||
|
|
||||||
## 迁移备注
|
|
||||||
|
|
||||||
自 TDLMPack 报告拆分迁入;状态字段保持 Pack 原文。未来扫描不再把 scan.sh exit 99、Semgrep、PMD 作为必跑流水线工具(历史正文中的提及可保留,本 README 不要求再跑它们)。
|
|
||||||
|
|
||||||
## 一、概况
|
|
||||||
|
|
||||||
| 项 | 值 |
|
|
||||||
|---|---|
|
|
||||||
| 仓库 | TDLM/thaumicadditions(git 仓,`src/` 直源) |
|
|
||||||
| 分支 · HEAD | `main` · `c49b5f03fb07907632830659ff83da18ab824c8c`(P2 扫描时 HEAD) |
|
|
||||||
| 最近更新 | 2026-10-29(P2) |
|
|
||||||
| 形态 | Forge 1.7.10 TC4 附属内容 mod(`Thaumic Additions - 0.41`,P2 起按实仓):java 307 / 32,017 行(src/main,无 kt/scala/Mixin);updateEntity 20、TESR 16(`ClientProxy.java:63-78`);`@SubscribeEvent` 含 PlayerTick/ClientTick/HUD;SimpleNetworkWrapper 通道 `thaumicadditions-playnet`;实体 4;构建走 Stratum 组织插件(`.github/workflows/build.yml`) |
|
|
||||||
| 工具 | 人工形态画像+候选式 grep+命中点全文回读;P2 覆 F8–F15 与 J5/J6 |
|
|
||||||
|
|
||||||
**计数矩阵**(处置 × 状态;合计 18)
|
|
||||||
|
|
||||||
| 处置\状态 | 待处理 | 待裁决 | 已延后 | 已驳回 | 已修复 |
|
|
||||||
|---|---|---|---|---|---|
|
|
||||||
| 修 | 0 | 0 | 0 | 0 | 4 |
|
|
||||||
| 观察 | 0 | 0 | 0 | 4 | 6 |
|
|
||||||
| 边界 | 0 | 0 | 0 | 2 | 2 |
|
|
||||||
| **合计** | **14** | 0 | 0 | 0 | **4** |
|
|
||||||
|
|
||||||
**扫描轮次**
|
|
||||||
|
|
||||||
| 轮次 | 日期 | SHA | 范围 | 净增(修/观/边) |
|
|
||||||
|---|---|---|---|---|
|
|
||||||
| P1 | 2026-10-26 | 2f7b9c9 | 建档:B1+D1 必扫+TE/TESR/包/封印/奇点热入口 | 4/10/3 |
|
|
||||||
| P2 | 2026-10-29 | c49b5f0 | F8–F15+J5/J6 过堂;F-005 同型补记(计数不变) | 0/0/1 |
|
|
||||||
|
|
||||||
## 四、命中(已记)
|
|
||||||
|
|
||||||
| 范式 | 定位 | 备注 |
|
|
||||||
|---|---|---|
|
|
||||||
| B1 | F-001、F-002 | concurrency;maven content |
|
|
||||||
| T4 | F-003、F-004 | 空转 TE |
|
|
||||||
| F1 | F-005、F-006、F-016 | TESR/创造节点/GUI(P2 同型补记 `TileRendererCreativeNode`) |
|
|
||||||
| S1 | F-007、F-008 | 奇点;收集印 |
|
|
||||||
| T1 | F-009–F-013 | 配方/重复 getTE/封印/管 |
|
|
||||||
| D1 | F-017 | 包路径 INFO |
|
|
||||||
| N1 | F-014 | 安全相邻 |
|
|
||||||
| T15 | F-015 | 储罐抽样 |
|
|
||||||
| F13 | F-018 | GUI 前景与 HUD 提示每帧重测文本宽度(边界) |
|
|
||||||
|
|
||||||
## 五、排除面
|
|
||||||
|
|
||||||
| 范式 | 排除码 | 依据 |
|
|
||||||
|---|---|---|
|
|
||||||
| T2 | E-守卫在位 | 未见无变化守卫即恒 `markDirty`/`markBlockForUpdate` 的周期路径;创造节点脏写在 `mfu` 门内(TileCreativeNode.java:145-147) |
|
|
||||||
| T3 | E-形态全零 | 无全服实例对齐同一 `worldTime%N` 周期谓词的 tick 群 |
|
|
||||||
| T5 | E-玩家回执 | `TileTaintedCrops` 反射仅坏土掉落分支(`:24-29`);`Class.forName` 在 TA/API 启动或交互沿 |
|
|
||||||
| T6 | E-守卫在位 | 主要 TE 工作含 `isRemote` 门(如 TileDarkGen/Infuser/Crystallizer);BlockVisTube.playerTick 为方块碰撞箱语义非无门世界扫描 |
|
|
||||||
| T7 | E-设计本体 | `Util.setBlockMetadata` 用 flag 2(Util.java:31)为元数据同步本体;未见无变化双通道失效广播热路径 |
|
|
||||||
| T8 | E-形态全零 | 配方表为 ArrayList 线性匹配已记 T1(F-009);无拼接键/契约破损 Map 热查询 |
|
|
||||||
| T9 | E-形态全零 | 自研实体为奇点/焦点弹/粒子,无「在地静止仍全价移动」物品实体形态 |
|
|
||||||
| T10 | E-形态全零 | 无红石粉式逐级衰减重通知链 |
|
|
||||||
| T11 | E-形态全零 | 无锁+装箱/弱键双查型热查询间接层 |
|
|
||||||
| T12 | E-形态全零 | 无长期混入未就绪项的工作队列全表 drain |
|
|
||||||
| T13 | E-设计本体 | SealCombo 每 tick new 已并入 F-012(T1);不另立临时对象条 |
|
|
||||||
| T14 | E-形态全零 | 全仓 `.stream()` 热路径 0 |
|
|
||||||
| F2 | E-形态全零 | 未见每帧 NBT 反序列化/深拷贝/全树文本重编译链 |
|
|
||||||
| F3 | E-形态全零 | 无超集过滤缺候选索引的热查询 |
|
|
||||||
| F4 | E-形态全零 | 同帧同参重复昂贵求值未独立确认(重复 getTE 归 T1) |
|
|
||||||
| F5 | E-形态全零 | TESR 无每帧射线/无节流世界反查主形态 |
|
|
||||||
| F6 | E-产品形态 | 无自研网格面剔除;渲染走 Model/原版通道 |
|
|
||||||
| F8 | E-守卫在位 | 16 个 TESR 于 `ClientProxy.java:63-78` 绑定,全仓 0 处覆写 `getMaxRenderDistanceSquared` ⇒ 走原版默认 4096(64 格)封顶;模型为 1 格级小几何,64 格处 1 格≈12 px(1080p、垂直 FOV 70°:1080/(2·tan35°·64)),再裁即可辨 ⇒ 无可裁点;每帧 `new Model`/RL 归 F-005 |
|
|
||||||
| F9 | E-形态全零 | `glFinish`/`glReadPixels`/`glGetInteger`/`glGetFloat`/`glGetBoolean`/`glGetError`/`glGetUniformLocation*`/`glGetAttribLocation` 全仓 0 命中;无同步点与回读面 |
|
|
||||||
| F10 | E-形态全零 | `glNewList`/`glCallList`/`compileDisplayList`/`glGenLists` 0;23 处 `setRotationAngles` 全在 `ModelBase` 子类 `render()` 内按原版约定调用或仅 `super` 转发(`ModelSeal.java:60`、`:94`),非输入未变仍全价重建 |
|
|
||||||
| F11 | E-设计本体 | 11 处发射全为玩法事件/封印工作态上的固定小数目:封印 reddust 每次 1 枚(`SealEventDestroySoil.java:37`、`SealEventTillSoil.java:37`)、熔炼结果 20 枚一次性(`SealEventItemSmelt.java:68`,栈耗尽即 `setDead`)、修复 1 枚(`SealEventItemRepairer.java:36`)、`randomDisplayTick` ≤10 枚(`BlockReturner.java:54`)、API 单枚(`APIProvide.java:40`、`AbstractParticle.java:34`);无每实例每帧无上限倾倒与拖尾无界追加 |
|
|
||||||
| F12 | E-形态全零 | `glBufferData`/`glBufferSubData`/`glGenBuffers`/`BufferManagement` 0;几何只经 Tessellator 立即模式提交 |
|
|
||||||
| F14 | E-形态全零 | `glUseProgram`/`glUniform*`/`ARBShaderObjects` 0,无自建着色器程序与逐元素 uniform 设定 |
|
|
||||||
| F15 | E-启动期 | 图集申请全在注册沿:`registerBlockIcons`(`BlockDarkGen.java:59` 等)、`registerIcons`(`FocusProjectile.java:34`)、`setTextureName`(`init/MF.java:34` 等);运行期无重复申请 |
|
|
||||||
| S2 | E-设计本体 | 周期 `getBlock`/`getTileEntity` 均为已加载邻域作业读取,非「结果可弃的试读加载」 |
|
|
||||||
| N2 | E-产品形态 | SimpleNetworkWrapper 1.7.10 主线程投递标准形态;无裸 Netty 业务线程改世界 |
|
|
||||||
| N3 | E-形态全零 | 未见无 shutdown 线程池或静态滞留 World/TE 注册表只增 |
|
|
||||||
| N4 | E-启动期 | `OpenLibDownloadEngine`/`TACore` 静态下载为类加载/coremod 沿;本提取无 META-INF 清单,运行可达性未证 |
|
|
||||||
| N5 | E-形态全零 | 出站包直接写 ByteBuf,无每包整份中间拷贝 |
|
|
||||||
| L1 | E-启动期 | 无 transformer 每类建全树/脚本 O(k·n) 注册表重扫;OpenLib 见 N4 |
|
|
||||||
| H1 | E-设计本体 | Infuser 事件 post 有配方完成语义;非「无订阅仍每实体每 tick 构造」 |
|
|
||||||
| M1 | E-形态全零 | 无长生命周期回调捕获仅创建时需要的宿主 |
|
|
||||||
| M2 | E-形态全零 | 未见本可 interning 的大量等价常驻谓词/形状重复创建热面 |
|
|
||||||
| J1 | E-形态全零 | 无已确认热路径上可 final 却阻碍内联的短链形态立案 |
|
|
||||||
| J2 | E-形态全零 | 热路径无定幂 `Math.pow`/仅比较用开方等未廉价化算式立案 |
|
|
||||||
| J3 | E-形态全零 | `parkNanos`/`yield`/`onSpinWait` 0 |
|
|
||||||
| J4 | E-形态全零 | 无基本类型数组同构手写循环可换批量原语的热面 |
|
|
||||||
| J5 | E-形态全零 | 粒子/TESR 非「同纹理逐元素 startDrawing…draw 成对未合并」主形态;P2 复核全仓 3 处 `startDrawingQuads` 各为单 quad 批(`RendererInfuser.java:69`、`TileRendererCreativeNode.java:48`、`HUD.java:191`) |
|
|
||||||
| J6 | E-形态全零 | 未见同一拍同源多谓词可融合的独立遍历立案;P2 复核封印路径为单趟扫事件表(`TileSeal.java:57-62`,频次已记 F-012) |
|
|
||||||
|
|
||||||
## 六、规则反馈
|
|
||||||
|
|
||||||
| 范式 | 盲区/建议 | 本仓锚点 |
|
|
||||||
|---|---|---|
|
|
||||||
| F1 | 反编译 TESR 常「每帧 new Model + new ResourceLocation」成对出现,规则文案可明示 Model 与 RL 同判 | F-005 RendererDarkGen.java:16/:22 |
|
|
||||||
| T1 | `Loader.isModLoaded` + `new` 桥接对象出现在 updateEntity 六向环,易被只扫配方表的规则漏掉 | F-011 TileThaumicGenerator.java:71 |
|
|
||||||
| S1 | 「盒有界但循环内重复查询同一盒」应明示计入频率乘子,勿因 radius 字面量有界直接排除 | F-007 EntitySingularity.java:70 |
|
|
||||||
| T4 | 1.7.10 默认 `canUpdate()==true`;无覆写 + 空/继承空 updateEntity 即命中,勿写「默认 false」 | F-003/F-004 |
|
|
||||||
| F8 | 1.7.10 `TileEntity.getMaxRenderDistanceSquared()` 默认 4096(64 格)即原版门;未覆写应记为门在位正例,勿把「没写 if(distance)」当缺门 | `ClientProxy.java:63-78` |
|
|
||||||
| F11 | 拟补判定款:固定小数目(1/≤10/一次性 20)且挂在玩法事件或工作态上的点光源发射,不算「无预算倾倒」;不认这条会把封印类与 `randomDisplayTick` 形态全拖进复核面 | `SealEventDestroySoil.java:37`、`BlockReturner.java:54` |
|
|
||||||
| F13 | 证据强度仍标「来源数 0」;本仓 9 个 GUI 前景+HUD 逐帧 `getStringWidth`(含 HUD 逐字符 `bindTexture`)可回填来源数,并明示「测宽=排版面、`drawString` 内部重测仍算一次」 | `GUIThaumicGenerator.java:32`、`TipMessage.java:35` |
|
|
||||||
|
|
||||||
## 七、修订史
|
|
||||||
|
|
||||||
| 日期 | 轮次 | 变更 |
|
|
||||||
|---|---|---|
|
|
||||||
| 2026-10-26 | P1 | 建档:修 4 / 观 10 / 边 3;源树 HEAD `2f7b9c9696ee6cceb11d93c54592fed30ca218de` |
|
|
||||||
| 2026-10-29 | P2 | F8–F15+J5/J6 过堂(SHA `c49b5f0`):F13 立 F-018(边界,GUI 前景 9 处+`TipMessage` 逐帧测宽);F8/F9/F10/F11/F12/F14/F15 入排除面;F-005 同型补记 `TileRendererCreativeNode`(计数不变);F-016 修法补量级算式(处置/状态不变);概况改按 git 实仓(HEAD `c49b5f0`@`main`),矩阵补合计行 → 边 3→4、合计 17→18、未关闭 13→14 |
|
|
||||||
@@ -40,6 +40,11 @@ public class BlockCreativeNode extends BlockContainer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public AxisAlignedBB getCollisionBoundingBoxFromPool(World w, int x, int y, int z) {
|
public AxisAlignedBB getCollisionBoundingBoxFromPool(World w, int x, int y, int z) {
|
||||||
|
if(!w.isRemote) {
|
||||||
|
// rendering never happens on the server, so the stack walk below can only find nothing
|
||||||
|
return AxisAlignedBB.getBoundingBox(0.0D, 0.0D, 0.0D, 0.0D, 0.0D, 0.0D);
|
||||||
|
}
|
||||||
|
|
||||||
StackTraceElement[] var5 = Thread.currentThread().getStackTrace();
|
StackTraceElement[] var5 = Thread.currentThread().getStackTrace();
|
||||||
int var6 = var5.length;
|
int var6 = var5.length;
|
||||||
|
|
||||||
|
|||||||
@@ -1,11 +1,13 @@
|
|||||||
package com.pengu.thaumcraft.additions.entity;
|
package com.pengu.thaumcraft.additions.entity;
|
||||||
|
|
||||||
import com.pengu.thaumcraft.additions.api.integration.ThaumicAdditionsDamage;
|
import com.pengu.thaumcraft.additions.api.integration.ThaumicAdditionsDamage;
|
||||||
|
import com.pengu.thaumcraft.additions.misc.TerritoryGuard;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import net.minecraft.entity.Entity;
|
import net.minecraft.entity.Entity;
|
||||||
import net.minecraft.entity.EntityLivingBase;
|
import net.minecraft.entity.EntityLivingBase;
|
||||||
import net.minecraft.entity.boss.EntityDragon;
|
import net.minecraft.entity.boss.EntityDragon;
|
||||||
import net.minecraft.entity.boss.EntityWither;
|
import net.minecraft.entity.boss.EntityWither;
|
||||||
|
import net.minecraft.entity.player.EntityPlayer;
|
||||||
import net.minecraft.entity.item.EntityItem;
|
import net.minecraft.entity.item.EntityItem;
|
||||||
import net.minecraft.init.Blocks;
|
import net.minecraft.init.Blocks;
|
||||||
import net.minecraft.item.ItemStack;
|
import net.minecraft.item.ItemStack;
|
||||||
@@ -58,7 +60,7 @@ public class EntitySingularity extends EntityAlumentum {
|
|||||||
++this.ticksExisted;
|
++this.ticksExisted;
|
||||||
if(this.ticksExisted >= 2000 || this.suckedItems >= 2000.0F) {
|
if(this.ticksExisted >= 2000 || this.suckedItems >= 2000.0F) {
|
||||||
for(p = 0; p < 5; ++p) {
|
for(p = 0; p < 5; ++p) {
|
||||||
this.worldObj.createExplosion(this, this.posX, this.posY, this.posZ, this.suckedItems / 200.0F, true);
|
this.worldObj.createExplosion(this, this.posX, this.posY, this.posZ, this.suckedItems / 200.0F, this.worldObj.getGameRules().getGameRuleBooleanValue("mobGriefing"));
|
||||||
}
|
}
|
||||||
|
|
||||||
this.setDead();
|
this.setDead();
|
||||||
@@ -137,7 +139,7 @@ public class EntitySingularity extends EntityAlumentum {
|
|||||||
i = (int)this.posX + this.worldObj.rand.nextInt(this.radius) - this.worldObj.rand.nextInt(this.radius);
|
i = (int)this.posX + this.worldObj.rand.nextInt(this.radius) - this.worldObj.rand.nextInt(this.radius);
|
||||||
var22 = (int)this.posY + this.worldObj.rand.nextInt(this.radius) - this.worldObj.rand.nextInt(this.radius);
|
var22 = (int)this.posY + this.worldObj.rand.nextInt(this.radius) - this.worldObj.rand.nextInt(this.radius);
|
||||||
var23 = (int)this.posZ + this.worldObj.rand.nextInt(this.radius) - this.worldObj.rand.nextInt(this.radius);
|
var23 = (int)this.posZ + this.worldObj.rand.nextInt(this.radius) - this.worldObj.rand.nextInt(this.radius);
|
||||||
if(this.worldObj.getBlock(i, var22, var23) != Blocks.air && this.worldObj.getBlock(i, var22, var23).getBlockHardness(this.worldObj, i, var22, var23) > -1.0F && this.worldObj.getGameRules().getGameRuleBooleanValue("mobGriefing")) {
|
if(this.worldObj.getBlock(i, var22, var23) != Blocks.air && this.worldObj.getBlock(i, var22, var23).getBlockHardness(this.worldObj, i, var22, var23) > -1.0F && this.worldObj.getGameRules().getGameRuleBooleanValue("mobGriefing") && this.canDestroy(i, var22, var23)) {
|
||||||
this.worldObj.getBlock(i, var22, var23).breakBlock(this.worldObj, i, var22, var23, this.worldObj.getBlock(i, var22, var23), 1);
|
this.worldObj.getBlock(i, var22, var23).breakBlock(this.worldObj, i, var22, var23, this.worldObj.getBlock(i, var22, var23), 1);
|
||||||
this.worldObj.playSoundEffect((double)i, (double)var22, (double)var23, this.worldObj.getBlock(i, var22, var23).stepSound.getBreakSound(), this.worldObj.getBlock(i, var22, var23).stepSound.getVolume(), this.worldObj.getBlock(i, var22, var23).stepSound.getPitch());
|
this.worldObj.playSoundEffect((double)i, (double)var22, (double)var23, this.worldObj.getBlock(i, var22, var23).stepSound.getBreakSound(), this.worldObj.getBlock(i, var22, var23).stepSound.getVolume(), this.worldObj.getBlock(i, var22, var23).stepSound.getPitch());
|
||||||
if(!this.worldObj.isRemote) {
|
if(!this.worldObj.isRemote) {
|
||||||
@@ -188,6 +190,17 @@ public class EntitySingularity extends EntityAlumentum {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** The player who threw it, or null (dispenser, merged singularity). Protection plugins read this by name. */
|
||||||
|
public EntityPlayer getOwnerEntity() {
|
||||||
|
EntityLivingBase t = this.getThrower();
|
||||||
|
return t instanceof EntityPlayer ? (EntityPlayer)t : null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Island/territory check: a BreakEvent as the thrower, or as a fake player when nobody threw it. */
|
||||||
|
private boolean canDestroy(int x, int y, int z) {
|
||||||
|
return TerritoryGuard.canRemoveBlock(this.worldObj, x, y, z, this.getOwnerEntity());
|
||||||
|
}
|
||||||
|
|
||||||
protected void onImpact(MovingObjectPosition m) {
|
protected void onImpact(MovingObjectPosition m) {
|
||||||
this.worldObj.playSoundEffect(this.posX, this.posY, this.posZ, "thaumicadditions:singularity", 16.0F, 1.0F);
|
this.worldObj.playSoundEffect(this.posX, this.posY, this.posZ, "thaumicadditions:singularity", 16.0F, 1.0F);
|
||||||
this.inGround = true;
|
this.inGround = true;
|
||||||
|
|||||||
@@ -0,0 +1,57 @@
|
|||||||
|
package com.pengu.thaumcraft.additions.misc;
|
||||||
|
|
||||||
|
import java.lang.ref.WeakReference;
|
||||||
|
|
||||||
|
import net.minecraft.entity.player.EntityPlayer;
|
||||||
|
import net.minecraft.world.World;
|
||||||
|
import net.minecraft.world.WorldServer;
|
||||||
|
|
||||||
|
import net.minecraftforge.common.MinecraftForge;
|
||||||
|
import net.minecraftforge.common.util.FakePlayer;
|
||||||
|
import net.minecraftforge.common.util.FakePlayerFactory;
|
||||||
|
import net.minecraftforge.event.world.BlockEvent;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Standard cancellable BlockEvent.BreakEvent gate for block removal that no player performs directly
|
||||||
|
* (void entity, hungry blocks, ...). Island and territory plugins receive the contract they already handle for player
|
||||||
|
* mining; the actor is the responsible player when there is one, otherwise a per-world fake player (which the
|
||||||
|
* protection layer judges as an unattributed machine). With no receiver nothing changes.
|
||||||
|
*/
|
||||||
|
public final class TerritoryGuard {
|
||||||
|
|
||||||
|
private static WeakReference<EntityPlayer> fallback = new WeakReference<>(null);
|
||||||
|
|
||||||
|
/** @param actor the player responsible for the removal, or null when there is none */
|
||||||
|
public static boolean canRemoveBlock(World world, int x, int y, int z, EntityPlayer actor) {
|
||||||
|
EntityPlayer who = resolveActor(world, actor);
|
||||||
|
if (who == null) {
|
||||||
|
// no world to attribute the event to (client world): nothing to protect
|
||||||
|
return !(world instanceof WorldServer);
|
||||||
|
}
|
||||||
|
BlockEvent.BreakEvent event = new BlockEvent.BreakEvent(
|
||||||
|
x,
|
||||||
|
y,
|
||||||
|
z,
|
||||||
|
world,
|
||||||
|
world.getBlock(x, y, z),
|
||||||
|
world.getBlockMetadata(x, y, z),
|
||||||
|
who);
|
||||||
|
return !MinecraftForge.EVENT_BUS.post(event);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static EntityPlayer resolveActor(World world, EntityPlayer actor) {
|
||||||
|
if (actor != null) return actor;
|
||||||
|
if (world instanceof WorldServer) {
|
||||||
|
EntityPlayer player = fallback.get();
|
||||||
|
if (player == null || player.worldObj != world) {
|
||||||
|
FakePlayer fake = FakePlayerFactory.getMinecraft((WorldServer) world);
|
||||||
|
player = fake;
|
||||||
|
fallback = new WeakReference<>(player);
|
||||||
|
}
|
||||||
|
return player;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private TerritoryGuard() {}
|
||||||
|
}
|
||||||
@@ -35,6 +35,7 @@ public class TileCreativeNode extends TileVisNode implements INode, IWandable {
|
|||||||
public Color targetColor = new Color(16777215);
|
public Color targetColor = new Color(16777215);
|
||||||
public Color color = new Color(16777215);
|
public Color color = new Color(16777215);
|
||||||
public boolean hasUpdatedOnce;
|
public boolean hasUpdatedOnce;
|
||||||
|
private boolean locationRegistered;
|
||||||
|
|
||||||
|
|
||||||
public void updateEntity() {
|
public void updateEntity() {
|
||||||
@@ -44,12 +45,51 @@ public class TileCreativeNode extends TileVisNode implements INode, IWandable {
|
|||||||
|
|
||||||
if(!this.hasUpdatedOnce) {
|
if(!this.hasUpdatedOnce) {
|
||||||
this.hasUpdatedOnce = !this.hasUpdatedOnce;
|
this.hasUpdatedOnce = !this.hasUpdatedOnce;
|
||||||
} else {
|
} else if(!this.locationRegistered || !this.isRegistrationIntact()) {
|
||||||
this.generateId();
|
this.generateId();
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* True while the shared location map still holds this node's entry unchanged. The old code rewrote the entry every
|
||||||
|
* tick, which also repaired it after another mod cleared or altered the map; checking it is one lookup and four
|
||||||
|
* int compares, and generateId runs again as soon as the entry is missing or different.
|
||||||
|
*/
|
||||||
|
private boolean isRegistrationIntact() {
|
||||||
|
if(this.id == null || TileNode.locations == null || this.worldObj == null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
java.util.List entry = (java.util.List)TileNode.locations.get(this.id);
|
||||||
|
if(entry == null || entry.size() != 4) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return Integer.valueOf(this.worldObj.provider.dimensionId).equals(entry.get(0))
|
||||||
|
&& Integer.valueOf(this.xCoord).equals(entry.get(1))
|
||||||
|
&& Integer.valueOf(this.yCoord).equals(entry.get(2))
|
||||||
|
&& Integer.valueOf(this.zCoord).equals(entry.get(3));
|
||||||
|
}
|
||||||
|
|
||||||
|
public void invalidate() {
|
||||||
|
this.unregisterLocation();
|
||||||
|
super.invalidate();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void onChunkUnload() {
|
||||||
|
this.unregisterLocation();
|
||||||
|
super.onChunkUnload();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void unregisterLocation() {
|
||||||
|
if(this.id != null && TileNode.locations != null) {
|
||||||
|
TileNode.locations.remove(this.id);
|
||||||
|
}
|
||||||
|
|
||||||
|
this.locationRegistered = false;
|
||||||
|
}
|
||||||
|
|
||||||
public AspectList getAspects() {
|
public AspectList getAspects() {
|
||||||
return (new AspectList()).add(Aspect.AIR, 134217).add(Aspect.WATER, 134217).add(Aspect.FIRE, 134217).add(Aspect.ORDER, 134217).add(Aspect.ENTROPY, 134217).add(Aspect.EARTH, 134217);
|
return (new AspectList()).add(Aspect.AIR, 134217).add(Aspect.WATER, 134217).add(Aspect.FIRE, 134217).add(Aspect.ORDER, 134217).add(Aspect.ENTROPY, 134217).add(Aspect.EARTH, 134217);
|
||||||
}
|
}
|
||||||
@@ -232,6 +272,7 @@ public class TileCreativeNode extends TileVisNode implements INode, IWandable {
|
|||||||
t.add(Integer.valueOf(this.yCoord));
|
t.add(Integer.valueOf(this.yCoord));
|
||||||
t.add(Integer.valueOf(this.zCoord));
|
t.add(Integer.valueOf(this.zCoord));
|
||||||
TileNode.locations.put(this.id, t);
|
TileNode.locations.put(this.id, t);
|
||||||
|
this.locationRegistered = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
return this.id;
|
return this.id;
|
||||||
|
|||||||
@@ -35,25 +35,17 @@ public class TileHyperNodeCreator extends TileThaumcraft implements IInventory,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
TileNode var5 = this.worldObj.getTileEntity(this.xCoord, this.yCoord + 1, this.zCoord) != null && this.worldObj.getTileEntity(this.xCoord, this.yCoord + 1, this.zCoord) instanceof TileNode?(TileNode)this.worldObj.getTileEntity(this.xCoord, this.yCoord + 1, this.zCoord):null;
|
net.minecraft.tileentity.TileEntity above = this.worldObj.getTileEntity(this.xCoord, this.yCoord + 1, this.zCoord);
|
||||||
|
TileNode var5 = above instanceof TileNode?(TileNode)above:null;
|
||||||
this.node = var5 != null;
|
this.node = var5 != null;
|
||||||
if(this.node) {
|
if(this.node) {
|
||||||
AspectList list = new AspectList();
|
// the node is only rewritten when it no longer holds the wanted amounts (drained, or the stock changed)
|
||||||
|
if(!holdsExactly(var5.getAspects(), totalItems, this.primalsOnly)) {
|
||||||
int corner;
|
var5.setAspects(wantedAspects(totalItems, this.primalsOnly));
|
||||||
for(corner = 0; corner < Aspect.getPrimalAspects().size(); ++corner) {
|
|
||||||
list.add((Aspect)Aspect.getPrimalAspects().get(corner), totalItems);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if(!this.primalsOnly) {
|
|
||||||
for(corner = 0; corner < Aspect.getCompoundAspects().size(); ++corner) {
|
|
||||||
list.add((Aspect)Aspect.getCompoundAspects().get(corner), totalItems);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
var5.setAspects(list);
|
|
||||||
if(this.worldObj.rand.nextBoolean()) {
|
if(this.worldObj.rand.nextBoolean()) {
|
||||||
corner = this.worldObj.rand.nextInt(8);
|
int corner = this.worldObj.rand.nextInt(8);
|
||||||
if(corner == 0) {
|
if(corner == 0) {
|
||||||
Thaumcraft.proxy.nodeBolt(this.worldObj, (float)this.xCoord, (float)this.yCoord + 2.0F, (float)this.zCoord, (float)this.xCoord + 0.5F, (float)this.yCoord + 1.5F, (float)this.zCoord + 0.5F);
|
Thaumcraft.proxy.nodeBolt(this.worldObj, (float)this.xCoord, (float)this.yCoord + 2.0F, (float)this.zCoord, (float)this.xCoord + 0.5F, (float)this.yCoord + 1.5F, (float)this.zCoord + 0.5F);
|
||||||
}
|
}
|
||||||
@@ -90,6 +82,52 @@ public class TileHyperNodeCreator extends TileThaumcraft implements IInventory,
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** The aspect list a node above gets: every primal (and unless primalsOnly every compound) at {@code total}. */
|
||||||
|
public static AspectList wantedAspects(int total, boolean primalsOnly) {
|
||||||
|
AspectList list = new AspectList();
|
||||||
|
|
||||||
|
int i;
|
||||||
|
for(i = 0; i < Aspect.getPrimalAspects().size(); ++i) {
|
||||||
|
list.add((Aspect)Aspect.getPrimalAspects().get(i), total);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!primalsOnly) {
|
||||||
|
for(i = 0; i < Aspect.getCompoundAspects().size(); ++i) {
|
||||||
|
list.add((Aspect)Aspect.getCompoundAspects().get(i), total);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return list;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Whether {@code current} already equals {@link #wantedAspects(int, boolean)} without building it. */
|
||||||
|
public static boolean holdsExactly(AspectList current, int total, boolean primalsOnly) {
|
||||||
|
if(current == null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
int expected = Aspect.getPrimalAspects().size() + (primalsOnly?0:Aspect.getCompoundAspects().size());
|
||||||
|
return current.size() == expected && allAmounts(current, total, primalsOnly);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static boolean allAmounts(AspectList current, int total, boolean primalsOnly) {
|
||||||
|
for(int i = 0; i < Aspect.getPrimalAspects().size(); ++i) {
|
||||||
|
if(current.getAmount((Aspect)Aspect.getPrimalAspects().get(i)) != total) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!primalsOnly) {
|
||||||
|
for(int i = 0; i < Aspect.getCompoundAspects().size(); ++i) {
|
||||||
|
if(current.getAmount((Aspect)Aspect.getCompoundAspects().get(i)) != total) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
public static boolean areItemStacksEqual(ItemStack s1, ItemStack s2) {
|
public static boolean areItemStacksEqual(ItemStack s1, ItemStack s2) {
|
||||||
return s1 == null && s2 == null?true:s1 != null && s2 != null && s1.getItem() == s2.getItem() && s1.getItemDamage() == s2.getItemDamage();
|
return s1 == null && s2 == null?true:s1 != null && s2 != null && s1.getItem() == s2.getItem() && s1.getItemDamage() == s2.getItemDamage();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -46,14 +46,17 @@ public class TileTankBasic extends TileThaumcraft implements ITubable {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
boolean var4 = this.worldObj.getTileEntity(this.xCoord, this.yCoord + 1, this.zCoord) instanceof TileTankBasic && this.vis + this.taint < this.capacity;
|
// each neighbour tile is looked up once; nothing between here and the uses changes the blocks around
|
||||||
|
net.minecraft.tileentity.TileEntity aboveTile = this.worldObj.getTileEntity(this.xCoord, this.yCoord + 1, this.zCoord);
|
||||||
|
boolean var4 = aboveTile instanceof TileTankBasic && this.vis + this.taint < this.capacity;
|
||||||
if(var4 && this.taint + this.vis > this.capacity - 5) {
|
if(var4 && this.taint + this.vis > this.capacity - 5) {
|
||||||
MagicType var5 = Math.max(this.taint, this.vis) == this.vis?MagicType.VIS:MagicType.TAINT;
|
MagicType var5 = Math.max(this.taint, this.vis) == this.vis?MagicType.VIS:MagicType.TAINT;
|
||||||
this.ejectVis(var5, ((ITubable)this.worldObj.getTileEntity(this.xCoord, this.yCoord + 1, this.zCoord)).acceptVis(var5, var5 == MagicType.VIS?this.vis:this.taint, ForgeDirection.DOWN), ForgeDirection.UP);
|
this.ejectVis(var5, ((ITubable)aboveTile).acceptVis(var5, var5 == MagicType.VIS?this.vis:this.taint, ForgeDirection.DOWN), ForgeDirection.UP);
|
||||||
}
|
}
|
||||||
|
|
||||||
if(this.worldObj.getTileEntity(this.xCoord, this.yCoord - 1, this.zCoord) instanceof TileTankBasic) {
|
net.minecraft.tileentity.TileEntity belowTile = this.worldObj.getTileEntity(this.xCoord, this.yCoord - 1, this.zCoord);
|
||||||
TileTankBasic var6 = (TileTankBasic)this.worldObj.getTileEntity(this.xCoord, this.yCoord - 1, this.zCoord);
|
if(belowTile instanceof TileTankBasic) {
|
||||||
|
TileTankBasic var6 = (TileTankBasic)belowTile;
|
||||||
if(var6.vis + var6.taint < var6.capacity - 5) {
|
if(var6.vis + var6.taint < var6.capacity - 5) {
|
||||||
for(int i = 5; i > 0; --i) {
|
for(int i = 5; i > 0; --i) {
|
||||||
if(this.vis >= i && var6.vis + var6.taint + i <= this.capacity - 5) {
|
if(this.vis >= i && var6.vis + var6.taint + i <= this.capacity - 5) {
|
||||||
|
|||||||
@@ -0,0 +1,278 @@
|
|||||||
|
# TDLM 补的中文名(thaumicadditions-0.41-06e47ff.jar 里 zh_CN 缺的键)。
|
||||||
|
# 只填 MC百科的中文名,或这个模组自己 zh_CN 里同一英文名的译法;不自己起名。
|
||||||
|
|
||||||
|
# Adaminite Boots ← MC百科 item/72510.html
|
||||||
|
item.thaumicadditions:adaminite_boots.name=元素靴子
|
||||||
|
# Adaminite Chestplate ← MC百科 item/72508.html
|
||||||
|
item.thaumicadditions:adaminite_chestplate.name=元素胸甲
|
||||||
|
# Adaminite Helmet ← MC百科 item/72507.html
|
||||||
|
item.thaumicadditions:adaminite_helmet.name=元素头盔
|
||||||
|
# §cAdaminite Ingot ← MC百科 item/72469.html
|
||||||
|
item.thaumicadditions:adaminite_ingot.name=元素锭
|
||||||
|
# Adaminite Leggings ← MC百科 item/72509.html
|
||||||
|
item.thaumicadditions:adaminite_leggings.name=元素护腿
|
||||||
|
# Adaminite Sword ← MC百科 item/72470.html
|
||||||
|
item.thaumicadditions:adaminite_sword.name=元素剑
|
||||||
|
# Arcane Dice ← MC百科 item/72503.html
|
||||||
|
item.thaumicadditions:arcane_dice.name=奥术骰子
|
||||||
|
# Arcane Transmutation Stone ← MC百科 item/72490.html
|
||||||
|
item.thaumicadditions:arcane_stone.name=嬗变之石
|
||||||
|
# Charged Adaminite Cap ← MC百科 item/72471.html
|
||||||
|
item.thaumicadditions:cap_adaminite.name=充能元素杖端
|
||||||
|
# Inert Adaminite Cap ← MC百科 item/72472.html
|
||||||
|
item.thaumicadditions:cap_adaminite_inert.name=惰性元素杖端
|
||||||
|
# Charged Mithrillium Cap ← MC百科 item/72477.html
|
||||||
|
item.thaumicadditions:cap_mithrillium.name=充能秘银杖端
|
||||||
|
# Inert Mithrillium Cap ← MC百科 item/72476.html
|
||||||
|
item.thaumicadditions:cap_mithrillium_inert.name=惰性秘银杖端
|
||||||
|
# Dark Infusion Recipe Book ← MC百科 item/72484.html
|
||||||
|
item.thaumicadditions:dark_infuser_book.name=黑暗注魔手册
|
||||||
|
# Depleted Shard ← MC百科 item/72480.html
|
||||||
|
item.thaumicadditions:depleted_shard.name=枯竭碎片
|
||||||
|
# Eldritch Keystone: Tlhutlh ← MC百科 item/72486.html
|
||||||
|
item.thaumicadditions:eldritch_keystone.tlhutlh.name=邪术基石: 充能
|
||||||
|
# Enchanted Greatwood ← MC百科 item/72500.html
|
||||||
|
item.thaumicadditions:enchanted_greatwood.name=蕴魔宏伟之木
|
||||||
|
# Enchanted Silverwood ← MC百科 item/72501.html
|
||||||
|
item.thaumicadditions:enchanted_silverwood.name=蕴魔银树原木
|
||||||
|
# Wand focus: Projectile ← MC百科 item/72505.html
|
||||||
|
item.thaumicadditions:foci_projectile.name=法杖核心:源动
|
||||||
|
# Wand focus: XP gain ← MC百科 item/72506.html
|
||||||
|
item.thaumicadditions:foci_xp.name=法杖核心:经验
|
||||||
|
# Eldritch Keystone: Inert ← MC百科 item/72485.html
|
||||||
|
item.thaumicadditions:inert_keystone.name=邪术基石:惰性
|
||||||
|
# Infusion Recipe Book ← MC百科 item/72483.html
|
||||||
|
item.thaumicadditions:infuser_book.name=符文注魔手册
|
||||||
|
# Mask Of Cruelty ← MC百科 item/72487.html
|
||||||
|
item.thaumicadditions:mask_of_cruelty.name=残忍面具
|
||||||
|
# §3Mithrillium Ingot ← MC百科 item/72475.html
|
||||||
|
item.thaumicadditions:mithrillium_ingot.name=秘银锭
|
||||||
|
# Quicksilver Core ← MC百科 item/72493.html
|
||||||
|
item.thaumicadditions:old_upgrade.0.name=水银核心
|
||||||
|
# Stabilized Singularity ← MC百科 item/72494.html
|
||||||
|
item.thaumicadditions:old_upgrade.1.name=稳定奇点
|
||||||
|
# Harnessed Rage ← MC百科 item/72495.html
|
||||||
|
item.thaumicadditions:old_upgrade.2.name=束缚怒火
|
||||||
|
# Concentrated Evil ← MC百科 item/72496.html
|
||||||
|
item.thaumicadditions:old_upgrade.3.name=浓缩邪恶
|
||||||
|
# Infinite Saddness ← MC百科 item/72497.html
|
||||||
|
item.thaumicadditions:old_upgrade.4.name=无限悲伤
|
||||||
|
# Contained Emptiness ← MC百科 item/72498.html
|
||||||
|
item.thaumicadditions:old_upgrade.5.name=禁锢空虚
|
||||||
|
# Collected Wisdom ← MC百科 item/72499.html
|
||||||
|
item.thaumicadditions:old_upgrade.6.name=汇集智慧
|
||||||
|
# Bucket Of Liquefied Warp ← MC百科 item/72511.html
|
||||||
|
item.thaumicadditions:pure_warp_bucket.name=咒波粘浆桶
|
||||||
|
# Seal Globe ← MC百科 item/72481.html
|
||||||
|
item.thaumicadditions:seal_globe.name=封印之球
|
||||||
|
# Arcane Seal ← MC百科 item/72492.html
|
||||||
|
item.thaumicadditions:seal_item.name=符文纹章
|
||||||
|
# Seal Symbol ← MC百科 item/72478.html
|
||||||
|
item.thaumicadditions:seal_symbol.name=符文符号
|
||||||
|
# Black Hole Core ← MC百科 item/72479.html
|
||||||
|
item.thaumicadditions:singcore.name=黑洞核心
|
||||||
|
# Arcane Singularity ← MC百科 item/72474.html
|
||||||
|
item.thaumicadditions:singularity.name=神秘奇点
|
||||||
|
# Soul Fragment ← MC百科 item/72482.html
|
||||||
|
item.thaumicadditions:soul_fragment.name=灵魂碎片
|
||||||
|
# Tainted Roots ← MC百科 item/72489.html
|
||||||
|
item.thaumicadditions:tainted_roots.name=腐化根系
|
||||||
|
# Tainted Seeds ← MC百科 item/72488.html
|
||||||
|
item.thaumicadditions:tainted_seed.name=腐化种子
|
||||||
|
# Arcane Transporter ← MC百科 item/72504.html
|
||||||
|
item.thaumicadditions:transporter.arcane.name=奥术转位仪
|
||||||
|
# §6Wand of Hallelujah ← MC百科 item/72502.html
|
||||||
|
item.thaumicadditions:wand_hallelujah.name=上帝权杖
|
||||||
|
# Adaminitewood Wand Rod ← MC百科 item/72473.html
|
||||||
|
item.thaumicadditions:wand_rod_adaminitewood.name=元素杖柄
|
||||||
|
# Adaminitewood Staff Core ← MC百科 item/72491.html
|
||||||
|
item.thaumicadditions:wand_staff_adaminitewood.name=元素杖芯
|
||||||
|
# Arcane Seal (Deprecated in NEI) ← MC百科 item/72447.html
|
||||||
|
tile.thaumicadditions:arc_seal.name=符文纹章 (Deprecated in NEI)
|
||||||
|
# Darkness Generator ← MC百科 item/72451.html
|
||||||
|
tile.thaumicadditions:dark_generator.name=黑暗发生器
|
||||||
|
# Dark Infuser ← MC百科 item/72450.html
|
||||||
|
tile.thaumicadditions:dark_infuser.name=黑暗注魔台
|
||||||
|
# Eldritch Stone ← MC百科 item/72459.html
|
||||||
|
tile.thaumicadditions:eldritch_stone.name=邪术石
|
||||||
|
# Vis filter ← MC百科 item/72467.html
|
||||||
|
tile.thaumicadditions:filter.name=要素过滤器
|
||||||
|
# Liquefied Warp ← MC百科 item/72468.html
|
||||||
|
tile.thaumicadditions:fluid.pure_warp.name=咒波粘浆
|
||||||
|
# [CREATIVE] Hyper node creator ← MC百科 item/72455.html
|
||||||
|
tile.thaumicadditions:hyper_node_creator.name=[创造模式]高速节点制造机
|
||||||
|
# Thaumic Infuser ← MC百科 item/72449.html
|
||||||
|
tile.thaumicadditions:infuser.name=符文注魔台
|
||||||
|
# Runic Matrix Activator ← MC百科 item/72457.html
|
||||||
|
tile.thaumicadditions:infuser_activator.name=自动注魔器
|
||||||
|
# Vis Condenser ← MC百科 item/72466.html
|
||||||
|
tile.thaumicadditions:old_condensator.name=要素结晶器
|
||||||
|
# Vis Crucible ← MC百科 item/72464.html
|
||||||
|
tile.thaumicadditions:old_crucible.name=要素坩埚
|
||||||
|
# Eldritch Stone Stairs ← MC百科 item/72463.html
|
||||||
|
tile.thaumicadditions:stairs_eldritch.name=邪术石楼梯
|
||||||
|
# Seal Symboller ← MC百科 item/72448.html
|
||||||
|
tile.thaumicadditions:symboller.name=符文注魔器
|
||||||
|
# Tainted Crops ← MC百科 item/72456.html
|
||||||
|
tile.thaumicadditions:tainted_crops.name=腐化作物
|
||||||
|
# [WIP] Vis tank ← MC百科 item/72446.html
|
||||||
|
tile.thaumicadditions:tank_basic.name=[WIP]要素存储器
|
||||||
|
# Thaumic Crystallizer ← MC百科 item/72452.html
|
||||||
|
tile.thaumicadditions:thaumic_crystallizer.name=神秘结晶器
|
||||||
|
# Thaumic Generator ← MC百科 item/72453.html
|
||||||
|
tile.thaumicadditions:thaumic_generator.name=神秘发生器
|
||||||
|
# Thaumic Restorer ← MC百科 item/72454.html
|
||||||
|
tile.thaumicadditions:thaumic_restorer.name=神秘修复机
|
||||||
|
# Tile Entity Booster ← MC百科 item/72458.html
|
||||||
|
tile.thaumicadditions:tile_booster.name=实体发射器
|
||||||
|
# Vis Conduit ← MC百科 item/72465.html
|
||||||
|
tile.thaumicadditions:vis_conduit.name=要素管道
|
||||||
|
# Void Chest ← MC百科 item/72461.html
|
||||||
|
tile.thaumicadditions:void_chest.name=虚空箱子
|
||||||
|
|
||||||
|
# 以下为 TDLM 翻译的说明、提示、界面和研究文本;其中的物品名按 MC百科或模组自带译名。
|
||||||
|
tc.research_category.THAUMICADDITIONS=神秘附加
|
||||||
|
tc.aspect.saxum=石,岩
|
||||||
|
tc.aspect.granum=种子
|
||||||
|
death.attack.thaumicadditions:invalidowner=%s 捡起了不属于自己的圣物
|
||||||
|
death.attack.thaumicadditions:singularity=%s 被分解成了粒子
|
||||||
|
item.Wand.ADAMINITE.cap=元素杖端
|
||||||
|
item.Wand.ADAMINITEWOOD.rod=元素
|
||||||
|
item.Wand.ADAMINITEWOOD_staff.rod=元素
|
||||||
|
fluid.thaumicadditions:fiquefied_warp=液化扭曲
|
||||||
|
seal.noeffect.globe=这个符文组合没有任何能力。
|
||||||
|
seal.tillsoil.1.globe=在 13×13 的范围内耕地,
|
||||||
|
seal.tillsoil.2.globe=耕地会一直保持湿润。
|
||||||
|
seal.breaksoil.1.globe=破坏 13×13 范围内的耕地。
|
||||||
|
seal.collect.globe=收集 16 格半径内的所有物品。
|
||||||
|
seal.harveset.globe=收获原版 Minecraft 中所有成熟的作物。
|
||||||
|
seal.repair.globe=消耗厘魔力(地)修复物品。
|
||||||
|
seal.fluxclean.globe=清除 16 格半径内的咒波。
|
||||||
|
seal.mechprot.globe=保护 16 格半径不受敌人侵扰。
|
||||||
|
seal.smelt.globe=消耗厘魔力(火)冶炼物品。
|
||||||
|
seal.whisper.globe=向附近所有玩家低语一些秘密……
|
||||||
|
seal.warp.1.globe=把 5 格半径内的所有玩家
|
||||||
|
seal.warp.2.globe=扭曲进时间的织物之中。
|
||||||
|
seal.teleportation.1.globe=用“位移护身符”点击来绑定。
|
||||||
|
seal.teleportation.2.globe=潜行时用护身符点击即可传送
|
||||||
|
tooltip.ta:aura_mode=光环伤害
|
||||||
|
tooltip.ta:craft_ingredient=合成材料
|
||||||
|
tooltip.ta:knowseverything=所有组合我都知道!
|
||||||
|
infusionbook.ta:magic_needed.desc=所需魔力
|
||||||
|
info.thaumicadditions:versioning.outdated=你的神秘附加版本已过时:%s!最新版本是 %s。
|
||||||
|
info.thaumicadditions:versioning.whatsnew=神秘附加 %s 的新内容:
|
||||||
|
info.thaumicadditions:versioning.no_connection=检查“神秘附加”最新版本失败:没有网络连接。
|
||||||
|
info.thaumicadditions:versioning.ok=你的“神秘附加”已是最新版本。
|
||||||
|
container.on=开
|
||||||
|
container.infuser=注魔器
|
||||||
|
container.infuserdark=黑暗注魔器
|
||||||
|
focus.upgrade.thaumicadditions:purity.text=弹射物击中实体时,会给它 30 秒的生命恢复;落在地面上时,会在落点周围散布纯净魔力,清除 8 格半径内的腐化。
|
||||||
|
focus.upgrade.thaumicadditions:infection.text=弹射物击中实体时,会给它 30 秒的咒波毒素;落在地面上时,会在落点周围散布腐化。
|
||||||
|
focus.upgrade.thaumicadditions:explosive.text=弹射物击中任何东西时,都会产生一次普通 TNT 威力的爆炸。等级越高,爆炸威力越大。
|
||||||
|
achievement.thaumicadditions:wand.wood=基础魔法
|
||||||
|
achievement.thaumicadditions:wand.wood.desc=合成一根任意杖端的木制法杖。
|
||||||
|
achievement.thaumicadditions:wand.greatwood=进阶魔法
|
||||||
|
achievement.thaumicadditions:wand.greatwood.desc=合成一根任意杖端的宏伟之木法杖。
|
||||||
|
achievement.thaumicadditions:wand.silverwood=高深魔法
|
||||||
|
achievement.thaumicadditions:wand.silverwood.desc=合成一根任意杖端的银树法杖。
|
||||||
|
achievement.thaumicadditions:wand.void=虚空魔法
|
||||||
|
achievement.thaumicadditions:wand.void.desc=合成任意一根虚空杖端的法杖。
|
||||||
|
achievement.thaumicadditions:block.crucible=神秘炼金:起步
|
||||||
|
achievement.thaumicadditions:block.crucible.desc=用法杖点击原版的炼药锅。
|
||||||
|
achievement.thaumicadditions:item.nitor=无尽的光!
|
||||||
|
achievement.thaumicadditions:item.nitor.desc=在坩埚里做出闪耀之光。
|
||||||
|
achievement.thaumicadditions:item.alumentum=魔法炸药
|
||||||
|
achievement.thaumicadditions:item.alumentum.desc=在坩埚里做出源动之焰。
|
||||||
|
achievement.thaumicadditions:item.thaumium=魔法之铁
|
||||||
|
achievement.thaumicadditions:item.thaumium.desc=在坩埚里做出神秘锭。
|
||||||
|
achievement.thaumicadditions:item.scribe=研究学徒
|
||||||
|
achievement.thaumicadditions:item.scribe.desc=合成任意一种笔与墨。
|
||||||
|
achievement.thaumicadditions:item.transporter=运输?没问题!
|
||||||
|
achievement.thaumicadditions:item.transporter.desc=做出神秘运输器。
|
||||||
|
achievement.thaumicadditions:item.primalpearl=忘了告诉大家了!
|
||||||
|
achievement.thaumicadditions:item.primalpearl.desc=获得元始珍珠。
|
||||||
|
achievement.thaumicadditions:creative.node=当个作弊者!
|
||||||
|
achievement.thaumicadditions:creative.node.desc=用法杖、权杖或法杖从创造模式灵气节点中汲取魔力。
|
||||||
|
tc.research_name.ADAMINITECRAFTING=元素锭合成
|
||||||
|
tc.research_text.ADAMINITECRAFTING=需要更好的东西吗?
|
||||||
|
r_adaminitecrafting.text=研究了神秘金属的一些特性之后,你发现可以用它做出好得多的东西。往神秘金属里注入一些钻石和几颗琥珀,就能得到元素锭。金属注魔时别忘了加入一些魔力布匹,否则神秘金属会衰变。
|
||||||
|
tc.research_name.ADAMINITESWORD=元素剑
|
||||||
|
tc.research_text.ADAMINITESWORD=谁想背着这把剑?
|
||||||
|
r_adaminitesword.text=在弄清那种奇妙物品的原理时,你想到可以做一件武器。一件令人毛骨悚然的武器。它不便宜,但威力很强。用法:潜行点击可切换伤害光环,对任何人造成 5、15 或 30 点伤害。注意,必须潜行才能产生临时的伤害光环;玩家不潜行时,光环会消散。
|
||||||
|
tc.research_name.CAP_ADAMINITE=元素杖端
|
||||||
|
tc.research_text.CAP_ADAMINITE=它真的比神秘杖端更好吗?
|
||||||
|
r_adaminite_cap.text=又发现了一样非常有用的东西。你渐渐变得疯狂,但最终能用那种红色金属为法杖做出新的杖端。使用前别忘了给它们充能。(觉醒方法在下一页)
|
||||||
|
tc.research_name.ROD_ADAMINITEWOOD=元素杖柄
|
||||||
|
tc.research_text.ROD_ADAMINITEWOOD=它能储存很多要素吗?
|
||||||
|
r_adaminitewood_rod.text=又发现了一样非常有用的东西。你变得更加疯狂了,但最终能用那种红色的锭为法杖做出新的魔法杖芯。这种杖芯每种要素都能储存整整 2000 点!
|
||||||
|
tc.research_name.ROD_ADAMINITEWOOD_staff=元素权杖
|
||||||
|
tc.research_text.ROD_ADAMINITEWOOD_staff=它真的比杖柄更好吗?
|
||||||
|
r_adaminitewood_staff.text=研究了法杖的种种好处之后,你把目光转向了元素杖柄,最终做出了元素权杖。<LINE>它能容纳整整 4500 点魔力!
|
||||||
|
tc.research_name.ADAMINITEARMOR=元素护甲
|
||||||
|
tc.research_text.ADAMINITEARMOR=我都说不清自己在做什么了……
|
||||||
|
r_adaminitearmor.text=又研究了一阵之后,你发现给任意一件神秘护甲注入 2 个元素锭和一些钻石,会得到一些有趣的东西。注意:必须靠近任意厘魔力来源,护甲的超能力才会激活:揭示之护目镜效果、恢复饱食度、加快回血(不需要饱食度)以及快速灭火。角色身上的护甲在闪烁,说明它所需的厘魔力已经充足。
|
||||||
|
tc.research_name.SINGULARITY=奇点
|
||||||
|
tc.research_text.SINGULARITY=有趣的东西,但很危险……
|
||||||
|
r_singularity.text=研究了源动之焰的特性之后,你意识到可以利用这一点为自己谋利。这只“野兽”能挖出又大又漂亮的矿洞,也能用来寻找稀有矿石。
|
||||||
|
tc.research_name.MITHRILLIUMCRAFTING=秘银锭合成
|
||||||
|
tc.research_text.MITHRILLIUMCRAFTING=耐用又实用!
|
||||||
|
r_mithrillium_ingot.text=秘银锭耐用,同时又灵活好用。往神秘金属里注入一些钻石和几颗琥珀,就能得到一种类似元素锭的金属,只是耐久不如它。金属注魔时别忘了加入一些魔力布匹,否则神秘金属会衰变。
|
||||||
|
tc.research_name.CAP_MITHRILLIUM=秘银杖端
|
||||||
|
tc.research_text.CAP_MITHRILLIUM=还有更方便的东西吗?
|
||||||
|
r_mithrillium_cap.text=研究秘银时,你想到可以用这种魔法金属做杖端。使用前别忘了给它们充能。(觉醒方法在下一页)
|
||||||
|
tc.research_name.ARCANESEAL=符文纹章
|
||||||
|
tc.research_text.ARCANESEAL=搬起来很轻松……
|
||||||
|
r_arcaneseal.text=每个神秘使都知道,咒语有特殊的功能。但这一切都需要一个依托,让人能放心使用而不必担心健康。很快你就想出了实现的办法,结果得到了符文纹章!<LINE>要给纹章上色,只需把染料和它一起放进工作台。如果给纹章涂了不止一种颜色,颜色会混合。
|
||||||
|
tc.research_name.SEALSYMBOLING=符文符号
|
||||||
|
tc.research_text.SEALSYMBOLING=为咒语而生……
|
||||||
|
r_sealsymboling.text=研究了符文纹章之后,你意识到咒语只能借助一种特殊的字符来书写,它们叫做符文符号。眼下你还没想好拿它做什么,但随着对神秘学的深入,你会找到它的用处。
|
||||||
|
tc.research_name.SEALSYMBOLLER=符文注魔器
|
||||||
|
tc.research_text.SEALSYMBOLLER=多彩的生活!
|
||||||
|
r_symboller.text=研究了符文符号之后,你发现它们本身毫无用处。但现在,借助魔法你造出了一台装置,它能从放在顶上的罐子里吸取源质,并把源质注入符文符号。现在你可以尽情摆弄符文符号和符文纹章了。
|
||||||
|
tc.research_name.SINGULARITYCORE=黑洞核心
|
||||||
|
tc.research_text.SINGULARITYCORE=比末影人还要黑。
|
||||||
|
r_singcore.text=研究秘银锭的特性时,你得出了一个理论:可以造出黑洞的核心。是的,黑洞核心对周围并不危险,但你能唤醒它吞噬一切、把一切分解成粒子的强大力量吗?
|
||||||
|
tc.research_name.INFUSER=注魔器
|
||||||
|
tc.research_text.INFUSER=用魔法注魔。
|
||||||
|
r_infuser.text=过去所有的神秘使都知道别的合成方式,但现在大家都把它们忘了。你想,如果能重现其中一种并加以利用,结果一定很有意思。
|
||||||
|
tc.research_name.INFUSERDARK=黑暗注魔台
|
||||||
|
tc.research_text.INFUSERDARK=黑暗魔法并不坏!
|
||||||
|
r_infuserdark.text.1=发现了另一种合成方式之后,你想到可以做些禁忌的东西。黑暗注魔台用来制作某些禁忌形态的资源。
|
||||||
|
r_infuserdark.text.2=<BR><IMG>thaumicadditions:textures/thaumonomicon/iri_dark_infuser.png:0:0:255:255:.65</IMG>
|
||||||
|
tc.research_name.TRANSMUTATIONSTONEARCANE=魔法嬗变
|
||||||
|
tc.research_text.TRANSMUTATIONSTONEARCANE=把这个变成魔法的那个!
|
||||||
|
r_arctrst.text=又研究了一阵之后,你发现了一种非常有趣的方法,可以得到奥术石、奥术石砖,甚至符文矩阵!这件强大的物品储存着全部元始能量,让施展魔法变得轻而易举。用它点击石头可得到奥术石,点击石砖可得到奥术石砖。潜行点击钻石块可得到符文矩阵。
|
||||||
|
tc.research_name.TAINTEDSEEDS=腐化作物
|
||||||
|
tc.research_text.TAINTEDSEEDS=腐化,腐化,腐化!!!
|
||||||
|
r_tainedseeds.text=大家都知道腐化不是什么好东西。但现在,你觉得自己能用魔法操纵它。你甚至可以给小麦种子注入腐化,得到腐化种子,它们能长在耕地、草方块和泥土上。可惜你还不知道它们能用来做什么……
|
||||||
|
tc.research_name.INFUSION_ACTIVATOR=注魔矩阵激活
|
||||||
|
tc.research_text.INFUSION_ACTIVATOR=是时候自动注魔了!
|
||||||
|
r_infusionmatrixactivator.text=在符文矩阵上做了一些合成之后,你已经点矩阵点得很累了。但聪明的神秘使不会永远点下去。于是你给元始魔力注魔,把它当作一小块记忆,开发出了一个有趣的装置,可以替你激活矩阵。有人放置这个方块时,它会记住方块的主人。<LINE>可惜,如果主人还没掌握合成前必须解锁的研究,矩阵激活器什么也不会做。
|
||||||
|
tc.research_name.ta:aspect_crafting=要素:%a
|
||||||
|
tc.research_text.ta:aspect_crafting=制作%a!
|
||||||
|
text.ta.research.aspects.crafting=本模组新增了要素%a。要制作%a,请使用%1a和%2a
|
||||||
|
tc.research_name.ENCHANTEDWOOD=蕴魔木材!
|
||||||
|
tc.research_text.ENCHANTEDWOOD=升级你的木头!
|
||||||
|
r_enchantedwood.text=现在你可以给以前见过的那些稀有木材注入元始魔法了。
|
||||||
|
tc.research_name.VISTRANSPORTEVOLVED=魔力输送进化!
|
||||||
|
tc.research_text.VISTRANSPORTEVOLVED=把魔力输送到四面八方!
|
||||||
|
r_visconduit.text=对蕴魔宏伟之木做了一番研究之后,你想起了那种以前没法输送的魔法液体……<LINE>但现在不一样了!你试着把蕴魔宏伟之木和一些玻璃组合起来,想看清流动的液体,最终得到了你想要的东西。
|
||||||
|
tc.research_name.VISCONDENSATOR=从空气中提取魔力!
|
||||||
|
tc.research_text.VISCONDENSATOR=这样对灵气有害吗?
|
||||||
|
r_viscondenser.text=对蕴魔木材做了更多研究之后,你又得出了一个理论:蕴魔木材的魔力传导性非常高,可以借助它从灵气中引出魔力。你把它们和一些铁按顺序组合起来,证实了这样做是值得的。<LINE>但先别高兴,它不是白干活的。必须在里面放一块任意的碎片才能运转。
|
||||||
|
tc.research_name.ARCANEDICE=奥术随机。
|
||||||
|
tc.research_text.ARCANEDICE=我该给你什么呢?……
|
||||||
|
r_dice_arcana.text=在研究元始珍珠的原初功能时,你发现它不仅有那些奇怪的机制,还蕴含着大量的随机性……<LINE>你把它和一些虚空金属、秘银组合起来,做出了奥术骰子。<LINE>你发现骰子并不会消耗珍珠,你的解释是:“骰子只从珍珠里取走随机性,而珍珠的随机性基本是无穷无尽的。”
|
||||||
|
tc.research_name.WANDFOCUSPROJECTILE=凭空射击!
|
||||||
|
tc.research_text.WANDFOCUSPROJECTILE=它能用来捣乱,还是帮忙?
|
||||||
|
r_foci_projectile.text=这个核心既能帮忙,也能让情况更糟,但要让它发挥作用,必须先在核心操纵台里升级。配方并不难……
|
||||||
|
tc.research_name.WANDFOCUSXP=把所有等级都给我!
|
||||||
|
tc.research_text.WANDFOCUSXP=那能把魔力换回来吗?
|
||||||
|
r_foci_xp.text=这个核心可以在核心操纵台里用“感染”升级。不升级时,它会消耗每种魔力各 10 点,给你 1 级经验。升级“感染”之后,它会抽走 1 级经验,往法杖里返还每种魔力各 10 点。
|
||||||
|
tc.research_name.ARCANETRANSPORTER=神秘运输器
|
||||||
|
tc.research_text.ARCANETRANSPORTER=它能搬基岩吗?
|
||||||
|
r_transporter.text=你需要经常搬运东西,于是发现了一种非常酷又便宜的方法,可以把任何方块搬到你想去的地方,包括箱子这类容器。<LINE>保证成功率:100%。
|
||||||
|
|
||||||
|
# ---- 以下为 TDLM 补的中文名(缺键清单补充)。只用 MC百科或本模组自带 zh_CN 的译法 ----
|
||||||
|
# Thaumic Additions ← 本模组自带:tc.research_category.THAUMICADDITIONS=神秘附加(同一英文名)
|
||||||
|
itemGroup.thaumicadditions=神秘附加
|
||||||
+113
@@ -0,0 +1,113 @@
|
|||||||
|
package com.pengu.thaumcraft.additions.tileentity;
|
||||||
|
|
||||||
|
import static org.junit.Assert.assertEquals;
|
||||||
|
import static org.junit.Assert.assertNotNull;
|
||||||
|
import static org.junit.Assert.assertNull;
|
||||||
|
import static org.junit.Assert.assertSame;
|
||||||
|
|
||||||
|
import java.lang.reflect.Constructor;
|
||||||
|
import java.lang.reflect.Field;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import net.minecraft.world.World;
|
||||||
|
import net.minecraft.world.WorldProviderSurface;
|
||||||
|
import net.minecraft.world.WorldServer;
|
||||||
|
import org.junit.Before;
|
||||||
|
import org.junit.Test;
|
||||||
|
import thaumcraft.common.tiles.TileNode;
|
||||||
|
|
||||||
|
/** TDLM/thaumicadditions#17: a creative node registers its location once, not every tick, and unregisters on removal. */
|
||||||
|
public class CreativeNodeRegistryTest {
|
||||||
|
|
||||||
|
private TileCreativeNode node;
|
||||||
|
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
private static <T> T allocate(Class<T> type) throws Exception {
|
||||||
|
Constructor<?> ctor = sun.reflect.ReflectionFactory.getReflectionFactory()
|
||||||
|
.newConstructorForSerialization(type, Object.class.getDeclaredConstructor());
|
||||||
|
return (T) ctor.newInstance();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Before
|
||||||
|
public void setUp() throws Exception {
|
||||||
|
if (TileNode.locations == null) {
|
||||||
|
Field f = TileNode.class.getDeclaredField("locations");
|
||||||
|
f.setAccessible(true);
|
||||||
|
f.set(null, new HashMap<String, ArrayList>());
|
||||||
|
}
|
||||||
|
TileNode.locations.clear();
|
||||||
|
World world = allocate(FixtureWorld.class);
|
||||||
|
Field provider = World.class.getDeclaredField("provider");
|
||||||
|
provider.setAccessible(true);
|
||||||
|
provider.set(world, new WorldProviderSurface());
|
||||||
|
this.node = allocate(TileCreativeNode.class);
|
||||||
|
this.node.setWorldObj(world);
|
||||||
|
this.node.xCoord = 3;
|
||||||
|
this.node.yCoord = 70;
|
||||||
|
this.node.zCoord = 5;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void locationIsPutOnceAcrossManyTicks() {
|
||||||
|
this.node.updateEntity(); // first tick only marks the node as updated
|
||||||
|
this.node.updateEntity();
|
||||||
|
ArrayList first = TileNode.locations.get("0:3:70:5");
|
||||||
|
assertNotNull(first);
|
||||||
|
for (int i = 0; i < 1000; i++) {
|
||||||
|
this.node.updateEntity();
|
||||||
|
}
|
||||||
|
assertSame("no re-registration on later ticks", first, TileNode.locations.get("0:3:70:5"));
|
||||||
|
assertEquals(1, TileNode.locations.size());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void unloadingRemovesTheLocationSoItCanBeRegisteredAgain() {
|
||||||
|
this.node.updateEntity();
|
||||||
|
this.node.updateEntity();
|
||||||
|
assertNotNull(TileNode.locations.get("0:3:70:5"));
|
||||||
|
this.node.onChunkUnload();
|
||||||
|
assertNull(TileNode.locations.get("0:3:70:5"));
|
||||||
|
this.node.updateEntity();
|
||||||
|
assertNotNull(TileNode.locations.get("0:3:70:5"));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void aClearedMapIsRepairedOnTheNextTick() {
|
||||||
|
this.node.updateEntity();
|
||||||
|
this.node.updateEntity();
|
||||||
|
assertNotNull(TileNode.locations.get("0:3:70:5"));
|
||||||
|
TileNode.locations.clear(); // another mod or TC4 wipes the shared map
|
||||||
|
this.node.updateEntity();
|
||||||
|
assertNotNull(TileNode.locations.get("0:3:70:5"));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void anAlteredEntryIsRestoredOnTheNextTick() {
|
||||||
|
this.node.updateEntity();
|
||||||
|
this.node.updateEntity();
|
||||||
|
ArrayList wrong = new ArrayList();
|
||||||
|
wrong.add(Integer.valueOf(9));
|
||||||
|
wrong.add(Integer.valueOf(9));
|
||||||
|
wrong.add(Integer.valueOf(9));
|
||||||
|
wrong.add(Integer.valueOf(9));
|
||||||
|
TileNode.locations.put("0:3:70:5", wrong);
|
||||||
|
this.node.updateEntity();
|
||||||
|
assertEquals(Integer.valueOf(3), TileNode.locations.get("0:3:70:5").get(1));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void anIntactEntryIsNotRewritten() {
|
||||||
|
this.node.updateEntity();
|
||||||
|
this.node.updateEntity();
|
||||||
|
ArrayList first = TileNode.locations.get("0:3:70:5");
|
||||||
|
this.node.updateEntity();
|
||||||
|
assertSame(first, TileNode.locations.get("0:3:70:5"));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class FixtureWorld extends WorldServer {
|
||||||
|
|
||||||
|
FixtureWorld() {
|
||||||
|
super(null, null, "node", 0, null, null);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
+47
@@ -0,0 +1,47 @@
|
|||||||
|
package com.pengu.thaumcraft.additions.tileentity;
|
||||||
|
|
||||||
|
import static org.junit.Assert.assertEquals;
|
||||||
|
import static org.junit.Assert.assertFalse;
|
||||||
|
import static org.junit.Assert.assertTrue;
|
||||||
|
|
||||||
|
import org.junit.Test;
|
||||||
|
import thaumcraft.api.aspects.Aspect;
|
||||||
|
import thaumcraft.api.aspects.AspectList;
|
||||||
|
|
||||||
|
/** TDLM/thaumicadditions#16: the node is only rewritten when it no longer holds what the creator wants. */
|
||||||
|
public class HyperNodeCreatorAspectsTest {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void aFreshlyBuiltListIsRecognisedAsCurrent() {
|
||||||
|
for (boolean primalsOnly : new boolean[] { false, true }) {
|
||||||
|
for (int total : new int[] { 0, 1, 64, 5000 }) {
|
||||||
|
AspectList list = TileHyperNodeCreator.wantedAspects(total, primalsOnly);
|
||||||
|
assertTrue("total " + total + " primalsOnly " + primalsOnly,
|
||||||
|
TileHyperNodeCreator.holdsExactly(list, total, primalsOnly));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void wantedListHasTheSameShapeAsBefore() {
|
||||||
|
AspectList all = TileHyperNodeCreator.wantedAspects(7, false);
|
||||||
|
assertEquals(Aspect.getPrimalAspects().size() + Aspect.getCompoundAspects().size(), all.size());
|
||||||
|
assertEquals(7, all.getAmount(Aspect.getPrimalAspects().get(0)));
|
||||||
|
assertEquals(Aspect.getPrimalAspects().size(), TileHyperNodeCreator.wantedAspects(7, true).size());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void aDrainedOrChangedNodeIsRewritten() {
|
||||||
|
AspectList list = TileHyperNodeCreator.wantedAspects(10, false);
|
||||||
|
list.reduce(Aspect.getPrimalAspects().get(0), 3);
|
||||||
|
assertFalse(TileHyperNodeCreator.holdsExactly(list, 10, false));
|
||||||
|
assertFalse(TileHyperNodeCreator.holdsExactly(TileHyperNodeCreator.wantedAspects(10, false), 11, false));
|
||||||
|
assertFalse(TileHyperNodeCreator.holdsExactly(TileHyperNodeCreator.wantedAspects(10, true), 10, false));
|
||||||
|
assertFalse(TileHyperNodeCreator.holdsExactly(null, 10, false));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void primalsOnlyDoesNotMatchAnUnrelatedFullList() {
|
||||||
|
assertFalse(TileHyperNodeCreator.holdsExactly(TileHyperNodeCreator.wantedAspects(10, false), 10, true));
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,153 @@
|
|||||||
|
package com.pengu.thaumcraft.additions.tileentity;
|
||||||
|
|
||||||
|
import static org.junit.Assert.assertEquals;
|
||||||
|
|
||||||
|
import java.lang.reflect.Constructor;
|
||||||
|
import java.lang.reflect.Field;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Random;
|
||||||
|
import net.minecraft.block.Block;
|
||||||
|
import net.minecraft.tileentity.TileEntity;
|
||||||
|
import net.minecraft.world.World;
|
||||||
|
import net.minecraft.world.WorldProviderSurface;
|
||||||
|
import net.minecraft.world.WorldServer;
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
/** TDLM/thaumicadditions#20: a tank looks each neighbour tile up once per tick and moves vis/taint exactly as before. */
|
||||||
|
public class TileTankBasicLookupTest {
|
||||||
|
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
private static <T> T allocate(Class<T> type) throws Exception {
|
||||||
|
Constructor<?> ctor = sun.reflect.ReflectionFactory.getReflectionFactory()
|
||||||
|
.newConstructorForSerialization(type, Object.class.getDeclaredConstructor());
|
||||||
|
return (T) ctor.newInstance();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class CountingWorld extends WorldServer {
|
||||||
|
|
||||||
|
Map<Long, TileEntity> tiles;
|
||||||
|
int tileLookups;
|
||||||
|
int blockLookups;
|
||||||
|
|
||||||
|
CountingWorld() {
|
||||||
|
super(null, null, "tanks", 0, null, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
static long key(int x, int y, int z) {
|
||||||
|
return ((long) x << 40) ^ ((long) y << 20) ^ z;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public TileEntity getTileEntity(int x, int y, int z) {
|
||||||
|
this.tileLookups++;
|
||||||
|
return this.tiles.get(key(x, y, z));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Block getBlock(int x, int y, int z) {
|
||||||
|
this.blockLookups++;
|
||||||
|
return null; // equals Blocks.air, which is unset without a Minecraft bootstrap
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getBlockMetadata(int x, int y, int z) {
|
||||||
|
this.blockLookups++;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static CountingWorld world() throws Exception {
|
||||||
|
CountingWorld world = allocate(CountingWorld.class);
|
||||||
|
world.rand = new Random(1);
|
||||||
|
Field provider = World.class.getDeclaredField("provider");
|
||||||
|
provider.setAccessible(true);
|
||||||
|
provider.set(world, new WorldProviderSurface());
|
||||||
|
world.isRemote = true; // no taint explosion branch
|
||||||
|
world.tiles = new HashMap<Long, TileEntity>();
|
||||||
|
return world;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static TileTankBasic tank(CountingWorld world, int y, int vis, int taint) throws Exception {
|
||||||
|
TileTankBasic tank = allocate(TileTankBasic.class);
|
||||||
|
tank.setWorldObj(world);
|
||||||
|
tank.xCoord = 3;
|
||||||
|
tank.yCoord = y;
|
||||||
|
tank.zCoord = 5;
|
||||||
|
tank.capacity = 1005;
|
||||||
|
tank.vis = vis;
|
||||||
|
tank.taint = taint;
|
||||||
|
world.tiles.put(CountingWorld.key(3, y, 5), tank);
|
||||||
|
return tank;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** The lookups of the old method, in order, on the same fields. */
|
||||||
|
private static void referenceUpdate(TileTankBasic t) {
|
||||||
|
World w = t.getWorldObj();
|
||||||
|
w.getBlock(t.xCoord, t.yCoord + 1, t.zCoord);
|
||||||
|
w.getBlock(t.xCoord, t.yCoord - 1, t.zCoord);
|
||||||
|
w.getBlockMetadata(t.xCoord, t.yCoord, t.zCoord);
|
||||||
|
boolean var4 = w.getTileEntity(t.xCoord, t.yCoord + 1, t.zCoord) instanceof TileTankBasic && t.vis + t.taint < t.capacity;
|
||||||
|
if (var4 && t.taint + t.vis > t.capacity - 5) {
|
||||||
|
TileTankBasic above = (TileTankBasic) w.getTileEntity(t.xCoord, t.yCoord + 1, t.zCoord);
|
||||||
|
int type = Math.max(t.taint, t.vis) == t.vis ? 0 : 1;
|
||||||
|
int q = above.acceptVis(type == 0 ? com.pengu.api.thaumicadditions.tubesyst.ITubable.MagicType.VIS : com.pengu.api.thaumicadditions.tubesyst.ITubable.MagicType.TAINT,
|
||||||
|
type == 0 ? t.vis : t.taint, net.minecraftforge.common.util.ForgeDirection.DOWN);
|
||||||
|
t.ejectVis(type == 0 ? com.pengu.api.thaumicadditions.tubesyst.ITubable.MagicType.VIS : com.pengu.api.thaumicadditions.tubesyst.ITubable.MagicType.TAINT, q,
|
||||||
|
net.minecraftforge.common.util.ForgeDirection.UP);
|
||||||
|
}
|
||||||
|
if (w.getTileEntity(t.xCoord, t.yCoord - 1, t.zCoord) instanceof TileTankBasic) {
|
||||||
|
TileTankBasic var6 = (TileTankBasic) w.getTileEntity(t.xCoord, t.yCoord - 1, t.zCoord);
|
||||||
|
if (var6.vis + var6.taint < var6.capacity - 5) {
|
||||||
|
for (int i = 5; i > 0; --i) {
|
||||||
|
if (t.vis >= i && var6.vis + var6.taint + i <= t.capacity - 5) {
|
||||||
|
var6.vis += i;
|
||||||
|
t.vis -= i;
|
||||||
|
}
|
||||||
|
if (t.taint >= i && var6.vis + var6.taint + i <= t.capacity - 5) {
|
||||||
|
var6.taint += i;
|
||||||
|
t.taint -= i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static int[] state(TileTankBasic... tanks) {
|
||||||
|
int[] out = new int[tanks.length * 2];
|
||||||
|
for (int i = 0; i < tanks.length; i++) {
|
||||||
|
out[2 * i] = tanks[i].vis;
|
||||||
|
out[2 * i + 1] = tanks[i].taint;
|
||||||
|
}
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void aStackOfTanksEndsInTheSameStateWithFewerLookups() throws Exception {
|
||||||
|
Random rnd = new Random(9);
|
||||||
|
for (int round = 0; round < 40; round++) {
|
||||||
|
int[] seedValues = new int[6];
|
||||||
|
for (int i = 0; i < 6; i++) {
|
||||||
|
seedValues[i] = rnd.nextInt(1000);
|
||||||
|
}
|
||||||
|
CountingWorld oldWorld = world();
|
||||||
|
CountingWorld newWorld = world();
|
||||||
|
TileTankBasic[] oldTanks = new TileTankBasic[3];
|
||||||
|
TileTankBasic[] newTanks = new TileTankBasic[3];
|
||||||
|
for (int i = 0; i < 3; i++) {
|
||||||
|
oldTanks[i] = tank(oldWorld, 64 + i, seedValues[2 * i], seedValues[2 * i + 1] % 500);
|
||||||
|
newTanks[i] = tank(newWorld, 64 + i, seedValues[2 * i], seedValues[2 * i + 1] % 500);
|
||||||
|
}
|
||||||
|
for (int tick = 0; tick < 30; tick++) {
|
||||||
|
for (int i = 0; i < 3; i++) {
|
||||||
|
referenceUpdate(oldTanks[i]);
|
||||||
|
newTanks[i].updateEntity();
|
||||||
|
}
|
||||||
|
org.junit.Assert.assertArrayEquals("round " + round + " tick " + tick, state(oldTanks), state(newTanks));
|
||||||
|
}
|
||||||
|
org.junit.Assert.assertTrue("the old method looks up at least as often", oldWorld.tileLookups >= newWorld.tileLookups);
|
||||||
|
assertEquals("new: two tile lookups per tank per tick", 2 * 3 * 30, newWorld.tileLookups);
|
||||||
|
assertEquals(oldWorld.blockLookups, newWorld.blockLookups);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,28 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
"""The singularity must ask the protection layer before removing a block and respect mobGriefing for its blast."""
|
||||||
|
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
ROOT = Path(__file__).resolve().parents[2]
|
||||||
|
SRC = (ROOT / "src/main/java/com/pengu/thaumcraft/additions/entity/EntitySingularity.java").read_text(encoding="utf-8")
|
||||||
|
GUARD = (ROOT / "src/main/java/com/pengu/thaumcraft/additions/misc/TerritoryGuard.java").read_text(encoding="utf-8")
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
assert "new BlockEvent.BreakEvent(" in GUARD and "EVENT_BUS.post(event)" in GUARD
|
||||||
|
assert "FakePlayerFactory.getMinecraft" in GUARD
|
||||||
|
|
||||||
|
# the block-eating branch is gated by the guard before any breakBlock / setBlockToAir
|
||||||
|
gate = SRC.index("this.canDestroy(i, var22, var23)")
|
||||||
|
assert gate < SRC.index(".breakBlock(this.worldObj, i, var22, var23"), "guard must precede breakBlock"
|
||||||
|
assert gate < SRC.index("this.worldObj.setBlockToAir(i, var22, var23)")
|
||||||
|
assert "TerritoryGuard.canRemoveBlock(this.worldObj, x, y, z, this.getOwnerEntity())" in SRC
|
||||||
|
|
||||||
|
# explosion attribution accessor, plus the end-of-life blast no longer ignores mobGriefing
|
||||||
|
assert "public EntityPlayer getOwnerEntity()" in SRC
|
||||||
|
assert 'this.suckedItems / 200.0F, true)' not in SRC
|
||||||
|
print("ok")
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
||||||
Reference in new issue
Block a user