Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

## 2.8.0-SNAPSHOT

- Removed the dedicated glow berry picking option; player harvesting now follows `player-block-interactions`.
- Added broad player block interaction controls with per-material overrides.
- Added player entity interaction and vehicle-entry controls.
- Added hanging entity detachment controls for item frames and paintings.
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ OpenPhysicsControl 是從零撰寫、採 MIT 授權的 Bukkit 世界物理控制

## 功能

86 項規則可按世界獨立控制,涵蓋方塊與流體、火焰與氣候、植物生長、實體物理、玩家互動、紅石以及自動化方塊。實驗性情境控制可停止玩家右鍵方塊、玩家操作或乘坐實體、展示框與畫脫落、床與重生錨的方塊來源爆炸、新放置方塊的初始連接,並以單一規則控制嗅探獸蛋完整孵化。預設值位於 `plugins/OpenPhysicsControl/default-rules.yml`,各世界狀態儲存在 `plugins/OpenPhysicsControl/worlds/<世界名稱>.yml`。設計與設定範例見 [`docs/scenario-controls.md`](docs/scenario-controls.md),完整事件來源及測試狀態見 [`docs/physics-matrix.md`](docs/physics-matrix.md)。
85 項規則可按世界獨立控制,涵蓋方塊與流體、火焰與氣候、植物生長、實體物理、玩家互動、紅石以及自動化方塊。實驗性情境控制可停止玩家右鍵方塊、玩家操作或乘坐實體、展示框與畫脫落、床與重生錨的方塊來源爆炸、新放置方塊的初始連接,並以單一規則控制嗅探獸蛋完整孵化。預設值位於 `plugins/OpenPhysicsControl/default-rules.yml`,各世界狀態儲存在 `plugins/OpenPhysicsControl/worlds/<世界名稱>.yml`。設計與設定範例見 [`docs/scenario-controls.md`](docs/scenario-controls.md),完整事件來源及測試狀態見 [`docs/physics-matrix.md`](docs/physics-matrix.md)。

`/opc` 開啟三列固定位置的物理分類選單,選擇分類後才會顯示該組規則;分類布局延續舊版熟悉的互動、建造、重力與流體、世界、生長區域,並加入機械分類。亦可使用 `/openphysics`、`/ophysics` 或 `/pc`。其他指令:

Expand Down
3 changes: 1 addition & 2 deletions docs/migration-from-dymeth-physicscontrol.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,6 @@ The old plugin exposed material- and actor-specific switches while OpenPhysicsCo
| `fire-ignite` | Player flint usage |
| `bone-meal` | `PLAYERS_BONE_MEAL_USAGE` and the older `BONE_MEAL_USAGE` name |
| `end-portal-frame-filling` | `END_PORTAL_FRAMES_FILLING` |
| `glow-berry-picking` | `GLOW_BERRIES_PICKING` |
| `block-hit-projectile-removal` | `BLOCK_HIT_PROJECTILES_REMOVING`; applies to arrows and tridents and remains `false` by default, as in the old plugin |
| `tnt-prime` | Burning arrows activating TNT |
| `farmland-trample`, `turtle-egg-trample`, `dripleaf-tilt`, `dragon-egg-teleport`, `frosted-ice` | Corresponding legacy physical-interaction triggers |
Expand All @@ -34,4 +33,4 @@ The old plugin exposed material- and actor-specific switches while OpenPhysicsCo
| `plant-spread`, `mushroom-growth`, `stem-growth`, `crop-growth`, `amethyst-growth` | Grass/mycelium, mushrooms, melons/pumpkins, crop, and amethyst triggers; exact material triggers use material overrides |
| `vertical-plant-growth`, `tree-growth`, `vine-growth`, `dripstone-growth` | Cane/cactus/chorus/kelp/bamboo, trees, vine variants/glow berries, and pointed dripstone triggers; all except broad tree growth use material overrides |

Legacy internal settings `DEBUG_MESSAGES`, `ALLOW_UNRECOGNIZED_ACTIONS`, and `IGNORED_STATE` are intentionally reported rather than imported.
The removed `GLOW_BERRIES_PICKING` switch and legacy internal settings `DEBUG_MESSAGES`, `ALLOW_UNRECOGNIZED_ACTIONS`, and `IGNORED_STATE` are intentionally reported rather than imported.
3 changes: 1 addition & 2 deletions docs/physics-matrix.md
Original file line number Diff line number Diff line change
Expand Up @@ -92,8 +92,7 @@ Two event surfaces have dedicated behavior. `explosion-block-damage` evaluates e
| `turtle-egg-trample` | Same physical interaction events | Turtle egg trampling | UT |
| `dripleaf-tilt` | Same physical interaction events | Big dripleaf tilt caused by entities | UT |
| `end-portal-frame-filling` | `PlayerInteractEvent`, `EntityChangeBlockEvent` | Placing an Eye of Ender into an End portal frame | MF |
| `glow-berry-picking` | `PlayerInteractEvent`, `EntityChangeBlockEvent` | Harvesting ripe glow berries from cave vines | MF |
| `player-block-interactions` | right-click `PlayerInteractEvent` | Direct use of clicked blocks, with per-material overrides; dedicated frame-filling and berry-picking rules are evaluated first | MF |
| `player-block-interactions` | right-click `PlayerInteractEvent` | Direct use of clicked blocks, including glow berry picking, with per-material overrides; dedicated frame-filling rules are evaluated first | MF |
| `player-entity-interactions` | `PlayerInteractEntityEvent`, `PlayerArmorStandManipulateEvent`, player `VehicleEnterEvent` | Direct entity use, armor stand manipulation, and mounting boats or minecarts | MF |
| `natural-mob-spawning` | `CreatureSpawnEvent` with `NATURAL` reason | Natural mob spawning only; commands, spawners, breeding, buckets, and plugins remain allowed | API |
| `spawner-mob-spawning` | `SpawnerSpawnEvent`, `TrialSpawnerSpawnEvent`, `CreatureSpawnEvent` with `SPAWNER`/`TRIAL_SPAWNER` reasons | Standard and trial spawner output; natural, command, breeding, bucket, and plugin spawns remain allowed | MF, UT, API |
Expand Down
2 changes: 1 addition & 1 deletion docs/scenario-controls.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ OpenPhysicsControl uses broad, composable behavior rules instead of copying ever
| `sniffer-egg-hatch` | `BlockGrowEvent`, `BlockFadeEvent` | Both sniffer-egg cracking stages and final hatching under one rule. |
| `placed-block-connections` | `BlockPlaceEvent` followed by a no-physics block-data update | Initial connections on newly placed fences, panes/bars, walls, stairs, fence gates, and chests. `block-updates` separately controls whether existing neighboring blocks react. |

Existing dedicated rules still run first. For example, End portal frame filling and glow berry picking retain their own switches before the broad player-block rule is evaluated. Redstone and machine processing remain separate from whether a player may interact with the block.
The dedicated End portal frame filling rule still runs before the broad player-block rule is evaluated. Glow berry picking is covered by `player-block-interactions` instead of a separate switch. Redstone and machine processing remain separate from whether a player may interact with the block.

## Configuration examples

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -112,7 +112,6 @@ private static Map<String, List<Rule>> mappings() {
put(result, Rule.FIRE_IGNITE, "PLAYERS_FLINT_USAGE");
put(result, Rule.BONE_MEAL, "BONE_MEAL_USAGE", "PLAYERS_BONE_MEAL_USAGE");
put(result, Rule.END_PORTAL_FRAME_FILLING, "END_PORTAL_FRAMES_FILLING");
put(result, Rule.GLOW_BERRY_PICKING, "GLOW_BERRIES_PICKING");
put(result, Rule.BLOCK_HIT_PROJECTILE_REMOVAL, "BLOCK_HIT_PROJECTILES_REMOVING");

put(result, Rule.TNT_PRIME, "BURNING_ARROWS_ACTIVATE_TNT");
Expand Down
13 changes: 0 additions & 13 deletions src/main/java/dev/openphysicscontrol/PhysicsEvents.java
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@
import org.bukkit.World;
import org.bukkit.block.Block;
import org.bukkit.block.BlockState;
import org.bukkit.block.data.type.CaveVinesPlant;
import org.bukkit.block.data.type.EndPortalFrame;
import org.bukkit.block.data.type.MangrovePropagule;
import org.bukkit.block.data.type.RespawnAnchor;
Expand Down Expand Up @@ -240,10 +239,6 @@ public void change(EntityChangeBlockEvent event) {
control(event, event.getBlock(), Rule.END_PORTAL_FRAME_FILLING);
return;
}
if (isGlowBerryHarvest(event)) {
control(event, event.getBlock(), Rule.GLOW_BERRY_PICKING);
return;
}
Rule rule;
Material material = event.getBlock().getType();
if (event.getEntity() instanceof FallingBlock) {
Expand Down Expand Up @@ -635,17 +630,9 @@ private static boolean isEndPortalFrameFilling(EntityChangeBlockEvent event) {
&& next.hasEye();
}

private static boolean isGlowBerryHarvest(EntityChangeBlockEvent event) {
return event.getBlock().getBlockData() instanceof CaveVinesPlant current
&& event.getBlockData() instanceof CaveVinesPlant next
&& current.isBerries()
&& !next.isBerries();
}

private static Rule rightClickRule(Material material) {
return switch (material) {
case END_PORTAL_FRAME -> Rule.END_PORTAL_FRAME_FILLING;
case CAVE_VINES, CAVE_VINES_PLANT -> Rule.GLOW_BERRY_PICKING;
default -> null;
};
}
Expand Down
1 change: 0 additions & 1 deletion src/main/java/dev/openphysicscontrol/Rule.java
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,6 @@ public enum Rule {
TURTLE_EGG_TRAMPLE(Group.PLAYERS, Material.TURTLE_HELMET),
DRIPLEAF_TILT(Group.PLAYERS, Material.BIG_DRIPLEAF),
END_PORTAL_FRAME_FILLING(Group.PLAYERS, Material.END_PORTAL_FRAME),
GLOW_BERRY_PICKING(Group.PLAYERS, Material.GLOW_BERRIES),
PLAYER_BLOCK_INTERACTIONS(Group.PLAYERS, Material.LEVER),
PLAYER_ENTITY_INTERACTIONS(Group.PLAYERS, Material.ITEM_FRAME),
NATURAL_MOB_SPAWNING(Group.MOBS, Material.ZOMBIE_SPAWN_EGG),
Expand Down
1 change: 0 additions & 1 deletion src/main/resources/default-rules.yml
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,6 @@ farmland-trample: true
turtle-egg-trample: true
dripleaf-tilt: true
end-portal-frame-filling: true
glow-berry-picking: true
player-block-interactions: true
player-entity-interactions: true
natural-mob-spawning: true
Expand Down
1 change: 0 additions & 1 deletion src/main/resources/lang/en.yml
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,6 @@ rule-farmland-trample: 'Farmland trampling'
rule-turtle-egg-trample: 'Turtle egg trampling'
rule-dripleaf-tilt: 'Big dripleaf tilting'
rule-end-portal-frame-filling: 'End portal frame filling'
rule-glow-berry-picking: 'Glow berry picking'
rule-player-block-interactions: 'Player block interactions'
rule-player-entity-interactions: 'Player entity interactions and mounting'
rule-natural-mob-spawning: 'Natural mob spawning'
Expand Down
1 change: 0 additions & 1 deletion src/main/resources/lang/zh_tw.yml
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,6 @@ rule-farmland-trample: '踐踏耕地'
rule-turtle-egg-trample: '踩碎海龜蛋'
rule-dripleaf-tilt: '大型垂滴葉傾斜'
rule-end-portal-frame-filling: '填入終界傳送門框架'
rule-glow-berry-picking: '採收螢光莓'
rule-player-block-interactions: '玩家與方塊互動'
rule-player-entity-interactions: '玩家與實體互動及乘坐'
rule-natural-mob-spawning: '生物自然生成'
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,16 +42,16 @@ void importsModernLegacyWorldRulesWithoutChangingTheSource() throws Exception {
YamlConfiguration migrated = YamlConfiguration.loadConfiguration(destination.toFile());
assertTrue(result.sourceFound());
assertEquals(source.toFile(), result.source());
assertEquals(8, result.importedRules());
assertTrue(result.unsupportedTriggers().isEmpty());
assertEquals(7, result.importedRules());
assertEquals(Set.of("GLOW_BERRIES_PICKING"), result.unsupportedTriggers());
assertFalse(migrated.contains("gravity"));
assertFalse(migrated.getBoolean("material-overrides.gravity.GRAVEL"));
assertTrue(migrated.getBoolean("material-overrides.gravity.SAND"));
assertFalse(migrated.getBoolean("water-flow"));
assertFalse(migrated.getBoolean("mob-griefing"));
assertFalse(migrated.getBoolean("frogspawn-hatch"));
assertFalse(migrated.getBoolean("bone-meal"));
assertFalse(migrated.getBoolean("glow-berry-picking"));
assertFalse(migrated.contains("glow-berry-picking"));
assertFalse(migrated.getBoolean("end-portal-frame-filling"));
assertTrue(migrated.getBoolean("block-hit-projectile-removal"));
assertEquals(sourceContent, Files.readString(source));
Expand Down Expand Up @@ -96,7 +96,7 @@ void importsEverySupportedCurrentLegacyTrigger() throws Exception {
"SNOW_GOLEMS_CREATE_SNOW", "WITHER_CREATE_WITHER_ROSE_BLOCKS",
"FROGSPAWN_LAYING_AND_SPAWNING", "PLAYERS_FLINT_USAGE", "BONE_MEAL_USAGE",
"PLAYERS_BONE_MEAL_USAGE", "BURNING_ARROWS_ACTIVATE_TNT", "FARMLANDS_TRAMPLING",
"END_PORTAL_FRAMES_FILLING", "GLOW_BERRIES_PICKING", "BLOCK_HIT_PROJECTILES_REMOVING",
"END_PORTAL_FRAMES_FILLING", "BLOCK_HIT_PROJECTILES_REMOVING",
"DRAGON_EGGS_TELEPORTING", "FROSTED_ICE_PHYSICS", "TURTLE_EGGS_TRAMPLING",
"DRIPLEAFS_LOWERING", "LADDERS_DESTROYING", "SIGNS_DESTROYING", "RAILS_DESTROYING",
"TORCHES_DESTROYING", "REDSTONE_TORCHES_DESTROYING", "SOUL_TORCHES_DESTROYING",
Expand All @@ -120,7 +120,7 @@ void importsEverySupportedCurrentLegacyTrigger() throws Exception {

Set<Rule> expected = Set.of(
Rule.MOB_GRIEFING, Rule.MOB_BLOCK_FORM, Rule.FROGSPAWN_HATCH, Rule.FIRE_IGNITE, Rule.BONE_MEAL,
Rule.END_PORTAL_FRAME_FILLING, Rule.GLOW_BERRY_PICKING, Rule.BLOCK_HIT_PROJECTILE_REMOVAL,
Rule.END_PORTAL_FRAME_FILLING, Rule.BLOCK_HIT_PROJECTILE_REMOVAL,
Rule.TNT_PRIME, Rule.FARMLAND_TRAMPLE, Rule.DRAGON_EGG_TELEPORT, Rule.FROSTED_ICE,
Rule.TURTLE_EGG_TRAMPLE, Rule.DRIPLEAF_TILT, Rule.BLOCK_UPDATES, Rule.GRAVITY, Rule.WATER_FLOW,
Rule.LAVA_FLOW, Rule.FIRE_SPREAD, Rule.SNOW_MELT, Rule.FARMLAND_DRY, Rule.ICE_MELT,
Expand Down
18 changes: 9 additions & 9 deletions tests/mineflayer/run.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -215,7 +215,7 @@ async function testRuleStorage (serverDir) {
assert.match(rules, /^ GRAVEL: false$/m, 'legacy gravel override was not imported')
assert.match(rules, /^bone-meal: false$/m, 'legacy bone meal alias was not imported')
assert.match(rules, /^end-portal-frame-filling: false$/m, 'legacy End portal frame setting was not imported')
assert.match(rules, /^glow-berry-picking: false$/m, 'legacy glow berry setting was not imported')
assert.doesNotMatch(rules, /^glow-berry-picking:/m, 'removed glow berry rule was persisted')
assert.match(rules, /^block-hit-projectile-removal: true$/m,
'legacy block-hit projectile cleanup setting was not imported')
} else if (file === 'world_nether.yml') {
Expand Down Expand Up @@ -261,7 +261,7 @@ async function testLocalizedMenu () {
slot: 4,
title: /玩家互動/,
size: 18,
rules: Array.from({ length: 9 }, (_, slot) => slot)
rules: [0, 1, 2, 3, 5, 6, 7, 8]
},
{
slot: 5,
Expand Down Expand Up @@ -780,7 +780,7 @@ async function testEndPortalFrameFilling () {
console.log('PASS end-portal-frame-filling')
}

async function testGlowBerryPicking () {
async function testGlowBerryPickingFollowsPlayerBlockInteractions () {
const position = [2, 102, 0]
async function ripeVine () {
await commands(
Expand All @@ -790,22 +790,22 @@ async function testGlowBerryPicking () {
await delay(250)
}

await commands('clear PhysicsBot', 'opc set glow-berry-picking off world')
await commands('clear PhysicsBot', 'opc set player-block-interactions off world')
await bot.unequip('hand')
await ripeVine()
await bot.activateBlock(await block(...position))
await delay(500)
assert.equal(String((await block(...position)).getProperties().berries), 'true',
'glow berry picking off: ripe cave vines were harvested')
'player block interactions off: ripe cave vines were harvested')

await commands('opc set glow-berry-picking on world')
await commands('opc set player-block-interactions on world')
await ripeVine()
await bot.activateBlock(await block(...position))
await delay(500)
assert.equal(String((await block(...position)).getProperties().berries), 'false',
'glow berry picking on: ripe cave vines were not harvested')
'player block interactions on: ripe cave vines were not harvested')
await commands('clear PhysicsBot', 'setblock 2 102 0 air', 'setblock 2 103 0 air')
console.log('PASS glow-berry-picking')
console.log('PASS glow berry picking follows player-block-interactions')
}

function nearbyArrows () {
Expand Down Expand Up @@ -1054,7 +1054,7 @@ async function start () {
await testPistons()
await testHangingMangroveMaturation()
await testEndPortalFrameFilling()
await testGlowBerryPicking()
await testGlowBerryPickingFollowsPlayerBlockInteractions()
await testBlockHitProjectileRemoval()
await testSpawnerMobSpawning()
await testOxygenDepletion()
Expand Down