diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml new file mode 100644 index 00000000..e3bc6fe9 --- /dev/null +++ b/.github/workflows/release.yml @@ -0,0 +1,88 @@ +name: Build & Publish Bedrock Addon + +permissions: + contents: write + +on: + release: + types: [published] + +jobs: + publish: + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v4 + + - name: Package mcaddon + run: | + VERSION=${{ github.event.release.tag_name }} + OUTPUT="Canopy-${VERSION}.mcaddon" + + mkdir build + cp -r "Canopy [BP]" "build/Canopy[BP]" + cp -r "Canopy [RP]" "build/Canopy[RP]" + cp LICENSE "build/Canopy[BP]" + cp LICENSE "build/Canopy[RP]" + + cd build + zip -r "$OUTPUT" "Canopy[BP]" "Canopy[RP]" + mv "$OUTPUT" .. + cd .. + + - name: Upload asset to GitHub Release + uses: softprops/action-gh-release@e798e6a1ede8d07b74ac4cdac6bdfa4cc1653907 + with: + files: Canopy-${{ github.event.release.tag_name }}.mcaddon + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + + - name: Upload to CurseForge + run: | + VERSION=${{ github.event.release.tag_name }} + + # Read the game version from manifest.json + MIN_ENGINE_VERSION=$(jq -r '.header.min_engine_version | @csv' "Canopy [BP]/manifest.json") + IFS=',' read -r LEADING MAJOR MINOR <<< "$MIN_ENGINE_VERSION" + ENGINE_PREFIX="${MAJOR}.${MINOR}" + + # Fetch all Bedrock versions from CurseForge API + CF_VERSIONS_JSON=$(curl -s -H "X-Api-Token: ${{ secrets.CF_API_TOKEN }}" \ + "https://minecraft-bedrock.curseforge.com/api/game/versions") + + # Extract all game version IDs whose name matches the game version from the manifest.json + GAME_VERSION_IDS=$(echo "$CF_VERSIONS_JSON" | jq -c --arg prefix "$ENGINE_PREFIX" ' + [ .[] | select(.name | startswith($prefix)) | .id ] + ') + if [ -z "$GAME_VERSION_IDS" ]; then + echo "No matching CurseForge versions found for engine prefix $ENGINE_PREFIX" + exit 1 + fi + echo "Found CurseForge version IDs for game version $ENGINE_PREFIX: $GAME_VERSION_IDS" + + # Use the Github release body as the changelog + CHANGELOG=$(jq -Rs . <<< "${{ github.event.release.body }}") + ADDON_FILENAME=Canopy-$VERSION.mcaddon + + # Upload the addon + RESPONSE=$(curl -s -X POST \ + -H "X-Api-Token: ${{ secrets.CF_API_TOKEN }}" \ + -F "metadata={ + \"changelog\": $CHANGELOG, + \"changelogType\": \"markdown\", + \"displayName\": \"$ADDON_FILENAME\", + \"releaseType\": \"release\", + \"gameVersions\": $GAME_VERSION_IDS + }" \ + -F "file=@$ADDON_FILENAME" \ + https://minecraft-bedrock.curseforge.com/api/projects/1062078/upload-file + ) + + UPLOADED_ID=$(echo "$RESPONSE" | jq -r '.id // empty') + if [ -n "$UPLOADED_ID" ]; then + echo "Successfully uploaded release. File ID: $UPLOADED_ID" + else + echo "Upload failed. Response:" + echo "$RESPONSE" + exit 1 + fi diff --git a/Canopy [BP]/manifest.json b/Canopy [BP]/manifest.json index 62cb2c26..5d38fb55 100644 --- a/Canopy [BP]/manifest.json +++ b/Canopy [BP]/manifest.json @@ -1,10 +1,10 @@ { "format_version": 2, "header": { - "name": "Canopy [BP] v1.5.3", + "name": "Canopy [BP] v1.5.4", "description": "Technical informatics & features addon by §aForestOfLight§r.", "uuid": "7f6b23df-a583-476b-b0e4-87457e65f7c0", - "version": [1, 5, 3], + "version": [1, 5, 4], "min_engine_version": [1, 26, 0] }, "modules": [ @@ -38,7 +38,7 @@ }, { "uuid": "bcf34368-ed0c-4cf7-938e-582cccf9950d", - "version": [1, 5, 3] + "version": [1, 5, 4] } ], "metadata": { diff --git a/Canopy [BP]/scripts/constants.js b/Canopy [BP]/scripts/constants.js index 2eaef276..68013522 100644 --- a/Canopy [BP]/scripts/constants.js +++ b/Canopy [BP]/scripts/constants.js @@ -1,4 +1,4 @@ -const PACK_VERSION = '1.5.3'; +const PACK_VERSION = '1.5.4'; const MC_VERSION = '1.26.0.2'; export { PACK_VERSION, MC_VERSION }; \ No newline at end of file diff --git a/Canopy [BP]/scripts/main.js b/Canopy [BP]/scripts/main.js index 1ff27cd8..ff31db85 100644 --- a/Canopy [BP]/scripts/main.js +++ b/Canopy [BP]/scripts/main.js @@ -77,6 +77,7 @@ import './src/rules/chunkBorders' import './src/rules/echoShardsEnableShriekers' import './src/rules/collisionBoxes' import './src/rules/potionBoostedBreeding' +import './src/rules/serverSideCollisionBoxes' // Load Time Processes import './src/onStart' diff --git a/Canopy [BP]/scripts/src/classes/BiomeEdgeRenderer.js b/Canopy [BP]/scripts/src/classes/BiomeEdgeRenderer.js index fc056b43..f96ec80c 100644 --- a/Canopy [BP]/scripts/src/classes/BiomeEdgeRenderer.js +++ b/Canopy [BP]/scripts/src/classes/BiomeEdgeRenderer.js @@ -138,7 +138,7 @@ export class BiomeEdgeRenderer { changeInFinalAxis[finalAxis] = quadHeight; const bound = new Vector(...changeInMiddleAxis).add(new Vector(...changeInFinalAxis)); - const worldLocation = Vector.from(this.blockVolume.getMin()).add(bound.multiply(0.5)).add(new Vector(...localLocation)); + const worldLocation = Vector.from(this.blockVolume.getMin()).add(new Vector(...localLocation)); worldLocation.dimension = this.dimension; const sidedBox = new DebugBox(worldLocation); sidedBox.bound = bound; @@ -168,7 +168,7 @@ export class BiomeEdgeRenderer { } renderAnalysisLocation(location) { - const dimensionLocation = Vector.from(location).add(new Vector(0.5, 0.5, 0.5)); + const dimensionLocation = Vector.from(location); dimensionLocation.dimension = this.dimension; const tempBox = new DebugBox(dimensionLocation); tempBox.color = { red: 1, green: 1, blue: 1 }; @@ -181,7 +181,7 @@ export class BiomeEdgeRenderer { drawAnalysisBoundingBox() { if (this.analysisBoundingBoxShape) this.analysisBoundingBoxShape.remove(); - const dimensionLocation = Vector.from(this.blockVolume.getMin()).add(Vector.from(this.blockVolume.getSpan()).multiply(0.5)); + const dimensionLocation = Vector.from(this.blockVolume.getMin()); dimensionLocation.dimension = this.dimension; const boundingBox = new DebugBox(dimensionLocation); boundingBox.bound = this.blockVolume.getSpan(); diff --git a/Canopy [BP]/scripts/src/classes/GeneratorChannel.js b/Canopy [BP]/scripts/src/classes/GeneratorChannel.js index 7b9fc89e..d334f7b2 100644 --- a/Canopy [BP]/scripts/src/classes/GeneratorChannel.js +++ b/Canopy [BP]/scripts/src/classes/GeneratorChannel.js @@ -1,5 +1,5 @@ import ItemCounterChannel from "./ItemCounterChannel"; -import { world, ItemStack } from "@minecraft/server"; +import { world, BlockComponentTypes, ItemStack } from "@minecraft/server"; class GeneratorChannel extends ItemCounterChannel { constructor(color) { @@ -22,17 +22,19 @@ class GeneratorChannel extends ItemCounterChannel { const generatedItems = []; for (const hopperGenerator of this.hopperList) { const hopper = world.getDimension(hopperGenerator.dimensionId).getBlock(hopperGenerator.location); - if (!hopper) continue; - const hopperContainer = hopper.getComponent('minecraft:inventory').container; - const itemStack = hopperContainer?.getItem(0); - if (itemStack) { - hopperGenerator.outputItemType = itemStack.typeId; - hopperGenerator.outputItemAmount = itemStack.amount; + if (!hopper) + continue; + const hopperContainer = hopper.getComponent(BlockComponentTypes.Inventory)?.container; + const itemStackToClone = hopperContainer?.getItem(0); + if (itemStackToClone) { + hopperGenerator.outputItemStack = itemStackToClone; } else { - if (hopperGenerator.outputItemType === null) + if (!(hopperGenerator.outputItemStack instanceof ItemStack)) continue; - hopperContainer.setItem(0, new ItemStack(hopperGenerator.outputItemType)); - generatedItems.push({ typeId: hopperGenerator.outputItemType, amount: 1 }); + const generatedItemStack = hopperGenerator.outputItemStack.clone(); + generatedItemStack.amount = 1; + hopperContainer.setItem(0, generatedItemStack); + generatedItems.push({ typeId: generatedItemStack.typeId, amount: 1 }); } } return generatedItems; diff --git a/Canopy [BP]/scripts/src/classes/HSSFinder.js b/Canopy [BP]/scripts/src/classes/HSSFinder.js index 39a0746b..bccd8828 100644 --- a/Canopy [BP]/scripts/src/classes/HSSFinder.js +++ b/Canopy [BP]/scripts/src/classes/HSSFinder.js @@ -95,7 +95,7 @@ export class HSSFinder { const top = this.findStructureTop(dimension, flooredLocation, "minecraft:fortress"); const height = top.y - bottom.y + 1; - const dimensionLocation = bottom.add(new Vector(0.5, height * 0.5, 0.5)); + const dimensionLocation = bottom; dimensionLocation.dimension = dimension; const box = new DebugBox(dimensionLocation); box.bound = new Vector(1, height, 1); diff --git a/Canopy [BP]/scripts/src/classes/HSSRenderer.js b/Canopy [BP]/scripts/src/classes/HSSRenderer.js index 02270a20..2c3c9a9e 100644 --- a/Canopy [BP]/scripts/src/classes/HSSRenderer.js +++ b/Canopy [BP]/scripts/src/classes/HSSRenderer.js @@ -23,7 +23,7 @@ export class HSSRenderer { } renderBoundingBox() { - const dimensionLocation = this.structureBounds.getCenterpoint(); + const dimensionLocation = this.structureBounds.getMin(); dimensionLocation.dimension = this.dimension; const box = new DebugBox(dimensionLocation); box.bound = this.structureBounds.getSize(); @@ -37,7 +37,7 @@ export class HSSRenderer { } renderSingleHSS(location) { - const bottom = new Vector(location.x + 0.5, this.structureBounds.getCenterpoint().y, location.z + 0.5); + const bottom = new Vector(location.x, this.structureBounds.getMin().y, location.z); bottom.dimension = this.dimension; const box = new DebugBox(bottom); box.bound = new Vector(1, this.structureBounds.getSize().y, 1); diff --git a/Canopy [BP]/scripts/src/classes/debugdisplay/AttackBox.js b/Canopy [BP]/scripts/src/classes/debugdisplay/AttackBox.js index a09bf687..4e18a64e 100644 --- a/Canopy [BP]/scripts/src/classes/debugdisplay/AttackBox.js +++ b/Canopy [BP]/scripts/src/classes/debugdisplay/AttackBox.js @@ -29,13 +29,13 @@ export class AttackBox extends DebugDisplayShapeElement { if (isProjectile) { const marginFromCenter = this.getProjectileMargin(); return { - location: new Vector(0, AABB.extent.y, 0), + location: Vector.from(AABB.center).subtract(marginFromCenter), size: marginFromCenter.multiply(2) }; } const marginFromCollisionBox = new Vector(0.8, 0, 0.8); return { - location: new Vector(0, AABB.extent.y, 0), + location: new Vector(-AABB.extent.x, 0, -AABB.extent.z).subtract(marginFromCollisionBox), size: Vector.from(AABB.extent).add(marginFromCollisionBox).multiply(2) }; } @@ -53,4 +53,8 @@ export class AttackBox extends DebugDisplayShapeElement { return true; return meleeMobs.includes(this.entity.typeId.replace("minecraft:", "")); } + + getClientSideLocation() { + return this.getAttackBox().location; + } } diff --git a/Canopy [BP]/scripts/src/classes/debugdisplay/CollisionBox.js b/Canopy [BP]/scripts/src/classes/debugdisplay/CollisionBox.js index 2149efc6..cb945d44 100644 --- a/Canopy [BP]/scripts/src/classes/debugdisplay/CollisionBox.js +++ b/Canopy [BP]/scripts/src/classes/debugdisplay/CollisionBox.js @@ -22,8 +22,12 @@ export class CollisionBox extends DebugDisplayShapeElement { getCollisionBox() { const AABB = this.entity.getAABB(); return { - location: new Vector(0, AABB.extent.y, 0), + location: new Vector(-AABB.extent.x, 0, -AABB.extent.z), size: Vector.from(AABB.extent).multiply(2) }; } + + getClientSideLocation() { + return this.getCollisionBox().location; + } } \ No newline at end of file diff --git a/Canopy [BP]/scripts/src/classes/debugdisplay/DebugDisplay.js b/Canopy [BP]/scripts/src/classes/debugdisplay/DebugDisplay.js index 6521c8c4..41c65734 100644 --- a/Canopy [BP]/scripts/src/classes/debugdisplay/DebugDisplay.js +++ b/Canopy [BP]/scripts/src/classes/debugdisplay/DebugDisplay.js @@ -201,6 +201,21 @@ export class DebugDisplay { return entityToDebugDisplayMap[entity.id]; } + static refreshAllElements() { + for (const debugDisplay of Object.values(entityToDebugDisplayMap)) { + const propertiesToRefresh = []; + for (const element of debugDisplay.getEnabledElements()) { + const property = Object.entries(debugableProperties).find(([, cls]) => element instanceof cls)?.[0]; + if (property) + propertiesToRefresh.push(property); + } + for (const property of propertiesToRefresh) { + debugDisplay.removeElement(property); + debugDisplay.addElement(property); + } + }; + } + static getDebugableProperties() { return Object.keys(debugableProperties); } diff --git a/Canopy [BP]/scripts/src/classes/debugdisplay/DebugDisplayShapeElement.js b/Canopy [BP]/scripts/src/classes/debugdisplay/DebugDisplayShapeElement.js index 7cb90680..393311a9 100644 --- a/Canopy [BP]/scripts/src/classes/debugdisplay/DebugDisplayShapeElement.js +++ b/Canopy [BP]/scripts/src/classes/debugdisplay/DebugDisplayShapeElement.js @@ -1,9 +1,12 @@ import { debugDrawer } from "@minecraft/debug-utilities"; import { DebugDisplayElement } from "./DebugDisplayElement"; +import { system } from "@minecraft/server"; +import { Rules } from "../../../lib/canopy/Canopy"; export class DebugDisplayShapeElement extends DebugDisplayElement { shapes = []; visibleToPlayer; + serverSidePositionRunner = void 0; constructor(entity, visibleToPlayer = void 0) { super(entity); @@ -15,6 +18,7 @@ export class DebugDisplayShapeElement extends DebugDisplayElement { destroy() { this.clearShapes(); + this.stopServerSidePositionRendering(); } createShapes() { @@ -23,10 +27,11 @@ export class DebugDisplayShapeElement extends DebugDisplayElement { clearShapes() { this.shapes.forEach(shape => debugDrawer.removeShape(shape)); + this.shapes.length = 0; } drawShape(debugShape) { - debugShape.attachedTo = this.entity; + this.setupPosition(debugShape); if (this.visibleToPlayer) debugShape.visibleTo = [this.visibleToPlayer]; this.shapes.push(debugShape); @@ -36,4 +41,30 @@ export class DebugDisplayShapeElement extends DebugDisplayElement { update() { throw new Error("Method 'update()' must be implemented."); } + + getClientSideLocation() { + throw new Error("Method 'getClientSideLocation()' must be implemented."); + } + + setupPosition(debugShape) { + if (Rules.getNativeValue('serverSideCollisionBoxes')) { + this.serverSidePositionRunner = system.runInterval(() => this.updateServerSidePosition()); + } else { + this.stopServerSidePositionRendering(); + debugShape.attachedTo = this.entity; + } + } + + updateServerSidePosition() { + const dimensionLocation = this.getClientSideLocation().add(this.entity.location); + dimensionLocation.dimension = this.entity.dimension; + this.shapes.forEach((debugShape) => debugShape.setLocation(dimensionLocation)); + } + + stopServerSidePositionRendering() { + if (this.serverSidePositionRunner !== void 0) { + system.clearRun(this.serverSidePositionRunner); + this.serverSidePositionRunner = void 0; + } + } } \ No newline at end of file diff --git a/Canopy [BP]/scripts/src/classes/debugdisplay/EyeLevel.js b/Canopy [BP]/scripts/src/classes/debugdisplay/EyeLevel.js index 53f3a733..100fc0ab 100644 --- a/Canopy [BP]/scripts/src/classes/debugdisplay/EyeLevel.js +++ b/Canopy [BP]/scripts/src/classes/debugdisplay/EyeLevel.js @@ -22,8 +22,12 @@ export class EyeLevel extends DebugDisplayShapeElement { getEyeLevelBoxBounds() { const AABB = this.entity.getAABB(); return { - location: new Vector(0, this.entity.getHeadLocation().y - this.entity.location.y, 0), + location: new Vector(-AABB.extent.x, this.entity.getHeadLocation().y - this.entity.location.y, -AABB.extent.z), size: new Vector(AABB.extent.x * 2, 0, AABB.extent.z * 2) } } + + getClientSideLocation() { + return this.getEyeLevelBoxBounds().location; + } } \ No newline at end of file diff --git a/Canopy [BP]/scripts/src/classes/debugdisplay/HitBox.js b/Canopy [BP]/scripts/src/classes/debugdisplay/HitBox.js index e9c0e4ae..aa5c0624 100644 --- a/Canopy [BP]/scripts/src/classes/debugdisplay/HitBox.js +++ b/Canopy [BP]/scripts/src/classes/debugdisplay/HitBox.js @@ -24,7 +24,7 @@ export class HitBox extends DebugDisplayShapeElement { const AABB = this.entity.getAABB(); const marginFromCollisionBox = this.getMargin(); return { - location: new Vector(0, AABB.extent.y, 0), + location: new Vector(-AABB.extent.x, 0, -AABB.extent.z).subtract(marginFromCollisionBox), size: Vector.from(AABB.extent).add(marginFromCollisionBox).multiply(2) }; } @@ -36,4 +36,8 @@ export class HitBox extends DebugDisplayShapeElement { return new Vector(1, 1, 1); return new Vector(0.1, 0.1, 0.1); } + + getClientSideLocation() { + return this.getHitBox().location; + } } \ No newline at end of file diff --git a/Canopy [BP]/scripts/src/classes/debugdisplay/ViewDirectionVector.js b/Canopy [BP]/scripts/src/classes/debugdisplay/ViewDirectionVector.js index d405e1a9..31ea668f 100644 --- a/Canopy [BP]/scripts/src/classes/debugdisplay/ViewDirectionVector.js +++ b/Canopy [BP]/scripts/src/classes/debugdisplay/ViewDirectionVector.js @@ -1,8 +1,9 @@ import { DebugDisplayShapeElement } from "./DebugDisplayShapeElement"; import { Vector } from "../../../lib/Vector"; import { DebugArrow } from "@minecraft/debug-utilities"; +import { serverSideCollisionBoxes } from "../../rules/serverSideCollisionBoxes"; -export class ViewDirectionVector extends DebugDisplayShapeElement { +export class ViewDirectionVector extends DebugDisplayShapeElement { createShapes() { const viewDirectionData = this.getViewDirectionBounds(); const dimensionLocation = { ...viewDirectionData.location, dimension: this.entity.dimension }; @@ -15,7 +16,10 @@ export class ViewDirectionVector extends DebugDisplayShapeElement { update() { const viewDirectionData = this.getViewDirectionBounds(); - this.shapes[0].endLocation = viewDirectionData.endLocation; + let endLocation = viewDirectionData.endLocation; + if (serverSideCollisionBoxes.getNativeValue()) + endLocation = endLocation.add(this.entity.location); + this.shapes[0].endLocation = endLocation; } getViewDirectionBounds() { @@ -26,4 +30,8 @@ export class ViewDirectionVector extends DebugDisplayShapeElement { endLocation: location.add(this.entity.getViewDirection()).multiply(1 + AABB.extent.x) }; } + + getClientSideLocation() { + return this.getViewDirectionBounds().location; + } } \ No newline at end of file diff --git a/Canopy [BP]/scripts/src/commands/pos.js b/Canopy [BP]/scripts/src/commands/pos.js index 6f34753c..9317c13d 100644 --- a/Canopy [BP]/scripts/src/commands/pos.js +++ b/Canopy [BP]/scripts/src/commands/pos.js @@ -19,8 +19,10 @@ new VanillaCommand({ }); function posCommand(origin, player) { - if (player && !isOp(origin) && !Rules.getNativeValue('commandPosOthers')) - return origin.sendMessage({ translate: 'rules.generic.blocked', with: ['commandPosOthers'] }); + if (player && !isOp(origin) && !Rules.getNativeValue('commandPosOthers')) { + origin.sendMessage({ translate: 'rules.generic.blocked', with: ['commandPosOthers'] }); + return; + } if (player?.length > 0) { for (const currPlayer of player) { if (!currPlayer) diff --git a/Canopy [BP]/scripts/src/rules/collisionBoxes.js b/Canopy [BP]/scripts/src/rules/collisionBoxes.js index db5250a9..e9e8183e 100644 --- a/Canopy [BP]/scripts/src/rules/collisionBoxes.js +++ b/Canopy [BP]/scripts/src/rules/collisionBoxes.js @@ -12,21 +12,23 @@ export class CollisionBoxes extends AbilityRule { identifier: 'collisionBoxes', onEnableCallback: () => {}, onDisableCallback: () => { - this.stopAllRenderingCollisionBoxes(); + this.stopAllRendering(); } }, { slotNumber: 14, - onPlayerEnableCallback: (player) => this.startRenderingCollisionBoxes(player.id), - onPlayerDisableCallback: (player) => this.stopRenderingCollisionBoxes(player.id) + onPlayerEnableCallback: (player) => this.startRendering(player.id), + onPlayerDisableCallback: (player) => this.stopRendering(player.id) }); } - stopAllRenderingCollisionBoxes() { - for (const playerId of Object.keys(this.runners)) - this.stopRenderingCollisionBoxes(playerId); + startRendering(playerId) { + if (this.runners[playerId]) + this.stopRendering(playerId); + this.collisionBoxRenderers[playerId] = {}; + this.runners[playerId] = system.runInterval(this.onTick.bind(this)); } - stopRenderingCollisionBoxes(playerId) { + stopRendering(playerId) { if (this.runners[playerId]) { system.clearRun(this.runners[playerId]); delete this.runners[playerId]; @@ -38,25 +40,30 @@ export class CollisionBoxes extends AbilityRule { } } - startRenderingCollisionBoxes(playerId) { - if (this.runners[playerId]) - this.stopRenderingCollisionBoxes(playerId); - this.collisionBoxRenderers[playerId] = {}; - this.runners[playerId] = system.runInterval(this.onTick.bind(this)); + refresh() { + for (const playerId of Object.keys(this.runners)) { + this.stopRendering(playerId); + this.startRendering(playerId); + } + } + + stopAllRendering() { + for (const playerId of Object.keys(this.runners)) + this.stopRendering(playerId); } onTick() { for (const playerId of Object.keys(this.runners)) { const player = world.getEntity(playerId); if (!player) { - this.stopRenderingCollisionBoxes(playerId); + this.stopRendering(playerId); continue; } - this.renderCollisionForNearbyEntities(player); + this.renderForNearbyEntities(player); } } - renderCollisionForNearbyEntities(player) { + renderForNearbyEntities(player) { const entities = this.getNearbyEntities(player).filter(entity => entity?.id !== player.id); const rendererMap = this.collisionBoxRenderers[player.id] || {}; @@ -78,4 +85,4 @@ export class CollisionBoxes extends AbilityRule { } } -export const hitboxes = new CollisionBoxes(); \ No newline at end of file +export const collisionBoxes = new CollisionBoxes(); \ No newline at end of file diff --git a/Canopy [BP]/scripts/src/rules/serverSideCollisionBoxes.js b/Canopy [BP]/scripts/src/rules/serverSideCollisionBoxes.js new file mode 100644 index 00000000..c0251f2a --- /dev/null +++ b/Canopy [BP]/scripts/src/rules/serverSideCollisionBoxes.js @@ -0,0 +1,23 @@ +import { BooleanRule, GlobalRule } from "../../lib/canopy/Canopy"; +import { DebugDisplay } from "../classes/debugdisplay/DebugDisplay"; +import { collisionBoxes } from "./collisionBoxes"; + +export class ServerSideCollisionBoxes extends BooleanRule { + runners = {}; + + constructor() { + super(GlobalRule.morphOptions({ + identifier: 'serverSideCollisionBoxes', + onEnableCallback: () => { + collisionBoxes.refresh(); + DebugDisplay.refreshAllElements(); + }, + onDisableCallback: () => { + collisionBoxes.refresh(); + DebugDisplay.refreshAllElements(); + } + })); + } +} + +export const serverSideCollisionBoxes = new ServerSideCollisionBoxes(); \ No newline at end of file diff --git a/Canopy [BP]/scripts/src/rules/tntFuse.js b/Canopy [BP]/scripts/src/rules/tntFuse.js index 323e9339..a8ba5989 100644 --- a/Canopy [BP]/scripts/src/rules/tntFuse.js +++ b/Canopy [BP]/scripts/src/rules/tntFuse.js @@ -14,10 +14,18 @@ class TNTFuseRule extends IntegerRule { subscribeToEvents() { world.afterEvents.entitySpawn.subscribe(this.onEntitySpawn.bind(this)); + world.afterEvents.entityLoad.subscribe(this.onEntityLoad.bind(this)); } onEntitySpawn(event) { - if (event.entity?.typeId !== 'minecraft:tnt' || event.cause === 'Event') return; + if (event.entity?.typeId !== 'minecraft:tnt' || event.cause === 'Event') + return; + this.startFuse(event.entity, this.getGlobalFuseTicks()); + } + + onEntityLoad(event) { + if (event.entity?.typeId !== 'minecraft:tnt') + return; this.startFuse(event.entity, this.getGlobalFuseTicks()); } diff --git a/Canopy [RP]/manifest.json b/Canopy [RP]/manifest.json index f7cc1ba0..889ace66 100644 --- a/Canopy [RP]/manifest.json +++ b/Canopy [RP]/manifest.json @@ -1,10 +1,10 @@ { "format_version": 2, "header": { - "name": "Canopy [RP] v1.5.3", + "name": "Canopy [RP] v1.5.4", "description": "Technical informatics & features addon by §aForestOfLight§r.", "uuid": "bcf34368-ed0c-4cf7-938e-582cccf9950d", - "version": [1, 5, 3], + "version": [1, 5, 4], "min_engine_version": [1, 26, 0] }, "modules": [ @@ -17,7 +17,7 @@ "dependencies": [ { "uuid": "7f6b23df-a583-476b-b0e4-87457e65f7c0", - "version": [1, 5, 3] + "version": [1, 5, 4] } ], "capabilities": [ diff --git a/Canopy [RP]/texts/en_US.lang b/Canopy [RP]/texts/en_US.lang index 0b3e9514..d63be263 100644 --- a/Canopy [RP]/texts/en_US.lang +++ b/Canopy [RP]/texts/en_US.lang @@ -394,6 +394,7 @@ rules.quickFillContainer.taken=§7Took all %1 from %2 rules.refillHand=Refills your hand with items from your inventory when you run out. Put an arrow in inventory slot 10 (next to the top left) to use. rules.renewableElytraDropChance=Gives phantoms a chance to drop elytra when killed by a shulker bullet. rules.renewableSponge=Guardians transform into elder guardians when hurt by lightning. +rules.serverSideCollisionBoxes=Renders collision boxes according to the entity's server position instead of its client position. rules.spawnEggSpawnWithMinecart=When using a spawn egg on a rail, the spawned entity will be placed in a minecart on the rail. rules.tntFuse=The TNT fuse time in ticks. rules.tntPrimeMomentum=Hardcodes the TNT prime momentum. diff --git a/Canopy [RP]/texts/ja_JP.lang b/Canopy [RP]/texts/ja_JP.lang index 60b2aa4a..7e3e292c 100644 --- a/Canopy [RP]/texts/ja_JP.lang +++ b/Canopy [RP]/texts/ja_JP.lang @@ -41,20 +41,21 @@ commands.butcher.fail.noneremoved=§c何も削除されませんでした。 commands.butcher.success=§7%1 を削除しました。 commands.butcher.success.many=§7%1 個のエンティティを削除しました: -commands.camera=カメラの設置/設置済みカメラ視点の切り替え/サバイバル対応スペクテイターモードの切り替え +commands.camera=カメラの設置、カメラ視点の切り替え、またはサバイバル対応スペクテイターモードの切り替えを行います。 commands.camera.spectate=サバイバル対応スペクテイターモードを切り替えます。 commands.camera.place.viewing=§cカメラ視点中はカメラを設置できません。 commands.camera.place.success=§7カメラを %s に設置しました。 -commands.camera.view.spectating=§cスペクテイター中はカメラを表示できません。 +commands.camera.view.spectating=§cスペクテイター中はカメラ視点に切り替えられません。 commands.camera.view.fail=§cまだカメラを設置していません。 commands.camera.view.dimension=§cこのカメラを見るには %s に移動してください。 -commands.camera.view.started=§aカメラ視点開始 -commands.camera.view.ended=§7カメラ視点終了 -commands.camera.spectate.viewing=§cカメラ視点中はスペクテイターできません。 +commands.camera.view.started=§aカメラ視点に切り替えました +commands.camera.view.ended=§7カメラ視点を終了しました +commands.camera.spectate.viewing=§cカメラ視点中はスペクテイターに切り替えられません。 commands.camera.spectate.gamemode=§cスペクテイター中はゲームモードを変更できません。 -commands.camera.spectate.started=§aスペクテイター開始 -commands.camera.spectate.ended=§7スペクテイター終了 -commands.camera.spectate.hardcore=§cスペクテイターを防止しました。ハードコアモードでのスペクテイターにはソフトロックバグがあります。これはMojangの問題です。 +commands.camera.spectate.started=§aスペクテイターに切り替えました +commands.camera.spectate.ended=§7スペクテイターを終了しました +commands.camera.spectate.hardcore=§cスペクテイターへの切り替えをブロックしました。ハードコアでのスペクテイターにはソフトロックのバグがあります(Mojangの問題です)。 +commands.camera.spectate.flying=§cスペクテイターに切り替えるには地面にいる必要があります。 commands.camera.invalidaction=§c無効なカメラアクションです。 commands.canopy=ルールを設定します。 @@ -83,7 +84,7 @@ commands.claimprojectiles.success.self=§7あなたの周囲 %2 ブロック以 commands.claimprojectiles.success.other=§7%3 の周囲 %2 ブロック以内の %1 個の投射物の所有者を変更しました。 commands.cleanup=範囲内のすべてのアイテムと経験値オーブを削除します。 -commands.cleanup.success=§7%1 体のエンティティをクリーンアップしました (半径%2ブロック)。 +commands.cleanup.success=§7%1 個のエンティティをクリーンアップしました (半径%2ブロック)。 commands.counter=ホッパーカウンターを管理します。(エイリアス: ct) commands.counter.channel.notfound=§c無効な色: %s。羊毛ブロックの色のいずれかを使用してください。 @@ -233,8 +234,8 @@ commands.peek=ターゲットのインベントリの中身を確認します。 commands.peek.fail.unloaded=§c%s のターゲットは読み込まれていません。 commands.peek.fail.noinventory=§c%2 の %1 にインベントリが見つかりません。 commands.peek.fail.noitems=§c%2 の %1 にアイテムが見つかりません。 -commands.peek.query.cleared=§7インベントリハイライトクエリをクリアしました。 -commands.peek.query.set=§7インベントリハイライトクエリを '%s' に設定しました。 +commands.peek.query.cleared=§7ピーククエリをクリアしました。 +commands.peek.query.set=§7ピーククエリを '%s' に設定しました。 commands.pos=現在の位置、または他のプレイヤーの位置を表示します。 commands.pos.self=§aあなたの位置: §f%s @@ -260,7 +261,7 @@ commands.simmap.config.reset=§7InfoDisplayシミュレーションマップの commands.sit=プレイヤーを座らせます。 commands.sit.busy=§cビジー状態のため座れません。 -commands.spawn=スポーンのトラッキング/モッキングのためのコマンド。 +commands.spawn=スポーンのトラッキングやモッキングを行うコマンド。 commands.spawn.entities=ワールド内のすべてのエンティティとその位置を一覧表示します。 commands.spawn.recent=過去30秒間のすべてのモブスポーンを表示します。モブ名を指定してフィルタリングできます。 commands.spawn.tracking.start=モブスポーンのトラッキングを開始します。座標を指定してエリア内をトラッキングできます。 @@ -327,8 +328,8 @@ commands.warp=ワープにテレポート、またはワープを管理します commands.warp.edit=ワープを追加または削除します。 commands.warp.tp=ワープにテレポートします。 commands.warp.list=利用可能なすべてのワープを一覧表示します。 -commands.warp.exists=§cワープ '%s' は既に存在します。ワープ一覧を見るには ./warps を使用してください。 -commands.warp.noexist=§cワープ '%s' が見つかりません。ワープ一覧を見るには ./warps を使用してください。 +commands.warp.exists=§cワープ '%s' は既に存在します。すべてのワープは ./warps で確認できます。 +commands.warp.noexist=§cワープ '%s' が見つかりません。すべてのワープは ./warps で確認できます。 commands.warp.add.success=§7ワープ '%s' を追加しました。 commands.warp.remove.success=§7ワープ '%s' を削除しました。 commands.warp.tp.fail.dimension=§c'%2' にテレポートするには %1 に移動してください。 @@ -341,7 +342,7 @@ rules.generic.unknown=§c無効なルール: '%1'。詳細は %2help を参照 rules.generic.invalidtype=§c無効な型: '%1' の値は %2 である必要があります。 rules.generic.outofrange=§c範囲外: '%1' の値は %2 から %3 の間である必要があります rules.generic.outofrange.withother= または次のいずれか: %s -rules.generic.blocked=§c%s ルールは無効です。 +rules.generic.blocked=§c%s ルールは無効化されています。 rules.generic.status=§7%1 : §l rules.generic.nochange=§7%1 は既に §l rules.generic.updated=§7%1 を更新: §l @@ -356,45 +357,46 @@ rules.hopperCounters='counter'コマンドとホッパーカウンター機能 rules.hopperGenerators='generator'コマンドとホッパージェネレーター機能を有効にします。 rules.commandJumpSurvival=サバイバルモードで'jump'コマンドを有効にします。 rules.commandPosOthers=オペレーター以外が他のプレイヤーに'pos'コマンドを使用することを許可します。 -rules.commandWarp=ワープおよび'warps'コマンドを有効にします。 -rules.commandWarpSurvival=サバイバルモードでワープおよび'warps'コマンドを有効にします。 +rules.commandWarp='warp'コマンドと'warps'コマンドを有効にします。 +rules.commandWarpSurvival=サバイバルモードで'warp'コマンドと'warps'コマンドを有効にします。 rules.allowBubbleColumnPlacement=気泡柱の設置制限を解除します。 rules.allowPeekInventory='peek'コマンドとpeekInventory InfoDisplayルールを有効にします。望遠鏡を使ったインベントリ確認も有効になります。 rules.armorStandRespawning=防具立てが投射物に当たると、アイテムをドロップしてリスポーンします。 rules.autoItemPickup=ブロックを破壊したときにアイテムを自動で拾います。 rules.carefulBreak=スニークしながらブロックを破壊したときにアイテムを自動で拾います。 -rules.cauldronConcreteConversion=コンクリートパウダーアイテムを水入り大釜の中に入れると、コンクリートアイテムに変換されます。 -rules.chunkBorders=インベントリスロット13(上段中央)に矢を入れると、チャンク境界を表示します。 -rules.collisionBoxes=インベントリスロット14(上段中央の右隣)に矢を入れると、エンティティの当たり判定を表示します。 -rules.creativeInstantTame=クリエイティブモードで、対応する食べ物を使って動物を即座に手懐けます。 +rules.cauldronConcreteConversion=コンクリートパウダーアイテムを水入り大釜の中に入れると、一定時間経過後にコンクリートアイテムに変換されます。 +rules.chunkBorders=チャンク境界を表示します。インベントリスロット13(上段中央)に矢を入れると有効になります。 +rules.collisionBoxes=エンティティの当たり判定を表示します。インベントリスロット14(上段中央の右隣)に矢を入れると有効になります。 +rules.creativeInstantTame=クリエイティブモードで、対応する食べ物を使って動物を即座に手懐けられるようにします。 rules.creativeNetherWaterPlacement=クリエイティブモードで、ネザーに水を置けるようにします。 rules.creativeNoTileDrops=クリエイティブモードで、破壊したブロックからアイテムがドロップしなくなります。 rules.creativeOneHitKill=クリエイティブモードのプレイヤーがあらゆるエンティティを一撃で倒せるようにします。スニーク中は近くのエンティティも倒します。 -rules.dupeTnt=TNTをピストンで動かし音符ブロックの隣で点火すると、TNTが複製できます。 +rules.dupeTnt=TNTをピストンで動かし音符ブロックの隣で点火すると、TNTを複製できるようにします。 rules.durabilityNotifier=ツールの耐久値が残り %s になったときに音と通知で知らせます。 rules.durabilityNotifier.alert=§c残り耐久値: %s -rules.durabilitySwap=耐久値0のアイテムを手から交換します。 -rules.echoShardsEnableShriekers=スカルクシュリーカーに残響の欠片を使用するとウォーデンを召喚できるようになります。 +rules.durabilitySwap=耐久値が0になったアイテムを手から外します。 +rules.echoShardsEnableShriekers=スカルクシュリーカーに残響の欠片を使用するとウォーデンを召喚できるようにします。 rules.entityInstantDeath=20gtの死亡アニメーションを削除します。エンティティは経験値もドロップしなくなります。 rules.explosionChainReactionOnly=爆発がTNTブロックのみに影響するようにします。 rules.explosionNoBlockDamage=爆発がブロックに影響しないようにします。 rules.explosionOff=爆発を完全に無効にします。 -rules.flippinArrows=矢をブロックに使うと、ブロックを反転・回転・または開くことができます。矢をオフハンドに持つと、ブロックの設置時に向きを反転して設置できます。 -rules.creativeHotbarSwitching=複数のホットバーのクイック切り替えを許可します。インベントリスロット17(右上)に矢を入れ、スニークしながらスクロールして切り替えます。 -rules.instaminableDeepslate=ネザライト、効率強化V、採掘速度上昇IIを使用してディープスレートを即座に壊せるようにします。 +rules.flippinArrows=矢をブロックに使うと、反転・回転・開閉できるようにします。矢をオフハンドに持つと、向きを反転してブロックを設置できます。 +rules.creativeHotbarSwitching=複数のホットバーを素早く切り替えられるようにします。インベントリスロット17(右上)に矢を入れ、スニークしながらスクロールして切り替えます。 +rules.instaminableDeepslate=ネザライト、効率強化V、採掘速度上昇IIを使用して深層岩を即座に壊せるようにします。 rules.instaminableEndstone=ネザライト、効率強化V、採掘速度上昇IIを使用してエンドストーンを即座に壊せるようにします。 rules.noWelcomeMessage=§lCanopy§r§8 のウェルカムメッセージを無効にします。 -rules.pistonBedrockBreaking=ピストンを岩盤ブロックから離れる方向に伸ばすと、岩盤を壊せるようにします。 +rules.pistonBedrockBreaking=ピストンが岩盤ブロックから離れる方向に伸びたとき、岩盤を壊せるようにします。 rules.playerSit=素早く %s 回スニークするとプレイヤーが座れるようになります。 -rules.quickFillContainer=インベントリスロット9(左上)に矢があるとき、アイテムを持ってコンテナを使うとそのアイテムをすべてコンテナに格納します。 +rules.potionBoostedBreeding=移動速度上昇のポーションが繁殖時のステータスに影響する挙動を再導入します。 +rules.quickFillContainer=アイテムを持ってコンテナを使うと、そのアイテムをすべてコンテナに格納します。インベントリスロット9(左上)に矢を入れると有効になります。 rules.quickFillContainer.filled=§7すべての %2 を %1 に収納しました rules.quickFillContainer.taken=§7%2 からすべての %1 を取り出しました -rules.refillHand=持っているアイテムが無くなったときにインベントリから補充します。インベントリスロット10(左上の右隣)に矢を入れて使用します。 +rules.refillHand=持っているアイテムが無くなったときにインベントリから補充します。インベントリスロット10(左上の右隣)に矢を入れると有効になります。 rules.renewableElytraDropChance=ファントムがシュルカーの弾で倒されると、確率でエリトラをドロップします。 rules.renewableSponge=ガーディアンが雷に打たれるとエルダーガーディアンに変化します。 rules.spawnEggSpawnWithMinecart=レールの上でスポーンエッグを使用すると、スポーンしたエンティティがトロッコに乗った状態で現れます。 rules.tntFuse=TNTの起爆時間(ティック単位)。 -rules.tntPrimeMomentum=TNT点火時の運動量を固定します。 +rules.tntPrimeMomentum=TNT着火時の運動量を固定値にします。 rules.universalChunkLoading=トロッコがスポーンしたとき、周囲5x5チャンクを10秒間読み込むようにします。 rules.infoDisplay.biome=現在の座標のバイオームを表示します。