Init
This commit is contained in:
9
.gitignore
vendored
Normal file
9
.gitignore
vendored
Normal file
@@ -0,0 +1,9 @@
|
||||
./node_modules
|
||||
./build
|
||||
|
||||
|
||||
node_modules
|
||||
build
|
||||
export
|
||||
.git
|
||||
|
||||
5
.idea/.gitignore
generated
vendored
Normal file
5
.idea/.gitignore
generated
vendored
Normal file
@@ -0,0 +1,5 @@
|
||||
# Default ignored files
|
||||
/shelf/
|
||||
/workspace.xml
|
||||
# Editor-based HTTP Client requests
|
||||
/httpRequests/
|
||||
12
.idea/Reeks2Missie6.iml
generated
Normal file
12
.idea/Reeks2Missie6.iml
generated
Normal file
@@ -0,0 +1,12 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<module type="WEB_MODULE" version="4">
|
||||
<component name="NewModuleRootManager">
|
||||
<content url="file://$MODULE_DIR$">
|
||||
<excludeFolder url="file://$MODULE_DIR$/.tmp" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/temp" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/tmp" />
|
||||
</content>
|
||||
<orderEntry type="inheritedJdk" />
|
||||
<orderEntry type="sourceFolder" forTests="false" />
|
||||
</component>
|
||||
</module>
|
||||
57
.idea/codeStyles/Project.xml
generated
Normal file
57
.idea/codeStyles/Project.xml
generated
Normal file
@@ -0,0 +1,57 @@
|
||||
<component name="ProjectCodeStyleConfiguration">
|
||||
<code_scheme name="Project" version="173">
|
||||
<HTMLCodeStyleSettings>
|
||||
<option name="HTML_SPACE_INSIDE_EMPTY_TAG" value="true" />
|
||||
</HTMLCodeStyleSettings>
|
||||
<JSCodeStyleSettings version="0">
|
||||
<option name="FORCE_SEMICOLON_STYLE" value="true" />
|
||||
<option name="SPACE_BEFORE_FUNCTION_LEFT_PARENTH" value="false" />
|
||||
<option name="FORCE_QUOTE_STYlE" value="true" />
|
||||
<option name="ENFORCE_TRAILING_COMMA" value="WhenMultiline" />
|
||||
<option name="SPACES_WITHIN_OBJECT_LITERAL_BRACES" value="true" />
|
||||
<option name="SPACES_WITHIN_IMPORTS" value="true" />
|
||||
</JSCodeStyleSettings>
|
||||
<TypeScriptCodeStyleSettings version="0">
|
||||
<option name="FORCE_SEMICOLON_STYLE" value="true" />
|
||||
<option name="SPACE_BEFORE_FUNCTION_LEFT_PARENTH" value="false" />
|
||||
<option name="FORCE_QUOTE_STYlE" value="true" />
|
||||
<option name="ENFORCE_TRAILING_COMMA" value="WhenMultiline" />
|
||||
<option name="SPACES_WITHIN_OBJECT_LITERAL_BRACES" value="true" />
|
||||
<option name="SPACES_WITHIN_IMPORTS" value="true" />
|
||||
</TypeScriptCodeStyleSettings>
|
||||
<VueCodeStyleSettings>
|
||||
<option name="INTERPOLATION_NEW_LINE_AFTER_START_DELIMITER" value="false" />
|
||||
<option name="INTERPOLATION_NEW_LINE_BEFORE_END_DELIMITER" value="false" />
|
||||
</VueCodeStyleSettings>
|
||||
<codeStyleSettings language="HTML">
|
||||
<option name="SOFT_MARGINS" value="120" />
|
||||
<indentOptions>
|
||||
<option name="INDENT_SIZE" value="2" />
|
||||
<option name="CONTINUATION_INDENT_SIZE" value="2" />
|
||||
<option name="TAB_SIZE" value="2" />
|
||||
</indentOptions>
|
||||
</codeStyleSettings>
|
||||
<codeStyleSettings language="JavaScript">
|
||||
<option name="SOFT_MARGINS" value="120" />
|
||||
<indentOptions>
|
||||
<option name="INDENT_SIZE" value="2" />
|
||||
<option name="CONTINUATION_INDENT_SIZE" value="2" />
|
||||
<option name="TAB_SIZE" value="2" />
|
||||
</indentOptions>
|
||||
</codeStyleSettings>
|
||||
<codeStyleSettings language="TypeScript">
|
||||
<option name="SOFT_MARGINS" value="120" />
|
||||
<indentOptions>
|
||||
<option name="INDENT_SIZE" value="2" />
|
||||
<option name="CONTINUATION_INDENT_SIZE" value="2" />
|
||||
<option name="TAB_SIZE" value="2" />
|
||||
</indentOptions>
|
||||
</codeStyleSettings>
|
||||
<codeStyleSettings language="Vue">
|
||||
<option name="SOFT_MARGINS" value="120" />
|
||||
<indentOptions>
|
||||
<option name="CONTINUATION_INDENT_SIZE" value="2" />
|
||||
</indentOptions>
|
||||
</codeStyleSettings>
|
||||
</code_scheme>
|
||||
</component>
|
||||
5
.idea/codeStyles/codeStyleConfig.xml
generated
Normal file
5
.idea/codeStyles/codeStyleConfig.xml
generated
Normal file
@@ -0,0 +1,5 @@
|
||||
<component name="ProjectCodeStyleConfiguration">
|
||||
<state>
|
||||
<option name="USE_PER_PROJECT_SETTINGS" value="true" />
|
||||
</state>
|
||||
</component>
|
||||
4
.idea/encodings.xml
generated
Normal file
4
.idea/encodings.xml
generated
Normal file
@@ -0,0 +1,4 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="Encoding" addBOMForNewFiles="with BOM under Windows, with no BOM otherwise" />
|
||||
</project>
|
||||
8
.idea/modules.xml
generated
Normal file
8
.idea/modules.xml
generated
Normal file
@@ -0,0 +1,8 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="ProjectModuleManager">
|
||||
<modules>
|
||||
<module fileurl="file://$PROJECT_DIR$/.idea/Reeks2Missie6.iml" filepath="$PROJECT_DIR$/.idea/Reeks2Missie6.iml" />
|
||||
</modules>
|
||||
</component>
|
||||
</project>
|
||||
10
.prettierrc.json
Normal file
10
.prettierrc.json
Normal file
@@ -0,0 +1,10 @@
|
||||
{
|
||||
"trailingComma": "es5",
|
||||
"tabWidth": 2,
|
||||
"semi": true,
|
||||
"singleQuote": false,
|
||||
"tabs": false,
|
||||
"backetSpacing": true,
|
||||
"arrowParens": "always",
|
||||
"printWidth": 120
|
||||
}
|
||||
7
.vscode/extensions.json
vendored
Normal file
7
.vscode/extensions.json
vendored
Normal file
@@ -0,0 +1,7 @@
|
||||
{
|
||||
"recommendations": [
|
||||
"esbenp.prettier-vscode",
|
||||
"blockceptionltd.blockceptionvscodeminecraftbedrockdevelopmentextension",
|
||||
"mojang-studios.minecraft-debugger"
|
||||
]
|
||||
}
|
||||
16
.vscode/launch.json
vendored
Normal file
16
.vscode/launch.json
vendored
Normal file
@@ -0,0 +1,16 @@
|
||||
{
|
||||
"version": "0.3.0",
|
||||
"configurations": [
|
||||
{
|
||||
"type": "minecraft-js",
|
||||
"request": "attach",
|
||||
"name": "Debug with Minecraft",
|
||||
"mode": "listen",
|
||||
"preLaunchTask": "build",
|
||||
"targetModuleUuid": "868bf88f-78d9-4109-b1b2-308645e367bd",
|
||||
"sourceMapRoot": "${workspaceFolder}/build/_Reeks2Missie6Debug",
|
||||
"generatedSourceRoot": "${workspaceFolder}/build/behavior_packs/scripts",
|
||||
"port": 19144
|
||||
}
|
||||
]
|
||||
}
|
||||
39
.vscode/settings.json
vendored
Normal file
39
.vscode/settings.json
vendored
Normal file
@@ -0,0 +1,39 @@
|
||||
{
|
||||
"[javascript]": {
|
||||
"editor.defaultFormatter": "esbenp.prettier-vscode"
|
||||
},
|
||||
"[typescript]": {
|
||||
"editor.defaultFormatter": "esbenp.prettier-vscode"
|
||||
},
|
||||
"[typescriptreact]": {
|
||||
"editor.defaultFormatter": "esbenp.prettier-vscode"
|
||||
},
|
||||
"[json]": {
|
||||
"editor.defaultFormatter": "esbenp.prettier-vscode"
|
||||
},
|
||||
"git.ignoreLimitWarning": true,
|
||||
"editor.formatOnSave": true,
|
||||
"search.exclude": {
|
||||
"**/.git": true,
|
||||
"**/node_modules": true,
|
||||
"**/build": true
|
||||
},
|
||||
"files.exclude": {
|
||||
"**/.DS_Store": true,
|
||||
"**/.git": true,
|
||||
"**/build": false,
|
||||
"**/node_modules": true
|
||||
},
|
||||
"cSpell.words": ["gametest", "gametests", "minecart", "shulker", "zoglin"],
|
||||
"editor.tabSize": 2,
|
||||
"workbench.colorCustomizations": {
|
||||
"activityBar.background": "#243b1e",
|
||||
"titleBar.activeBackground": "#1f3d21",
|
||||
"titleBar.activeForeground": "#F5FCEB"
|
||||
},
|
||||
|
||||
"emeraldwalk.runonsave": {
|
||||
"commands": [{ "cmd": "gulp", "isAsync": true, "match": "\\.ts$" }]
|
||||
},
|
||||
"BC-MC.Education.Enable": true
|
||||
}
|
||||
12
.vscode/tasks.json
vendored
Normal file
12
.vscode/tasks.json
vendored
Normal file
@@ -0,0 +1,12 @@
|
||||
{
|
||||
"version": "2.0.0",
|
||||
"tasks": [
|
||||
{
|
||||
"label": "build",
|
||||
"dependsOrder": "sequence",
|
||||
"dependsOn": [
|
||||
"gulp: default"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
50
README.md
Normal file
50
README.md
Normal file
@@ -0,0 +1,50 @@
|
||||
# Codefever Typescript level framework
|
||||
|
||||
This is the readme for the typescript framework for minecraft education
|
||||
|
||||
# Terminology
|
||||
|
||||
## Puppeteer
|
||||
|
||||
Puppeteer is a class that handles all the UI code for displaying messages to the player. It also handles translations. see [Translations](#translations)
|
||||
|
||||
## MindKeeper
|
||||
|
||||
This is the system that handles all the world storage, supported types are `boolean`, `number`, `string`
|
||||
|
||||
> **Important** : all registering of the world variables must be done in the world.afterEvents.worldInitialize event (this event can't send anything to the world (like messages))
|
||||
>
|
||||
> Here is a example of a definition of the world variable foo
|
||||
|
||||
```typescript
|
||||
world.afterEvents.worldInitialize.subscribe(({ propertyRegistry }) => {
|
||||
mindKeeper.registerStore("foo", StoreType.string);
|
||||
|
||||
mindKeeper.registerToWorld(propertyRegistry);
|
||||
});
|
||||
```
|
||||
|
||||
## Level (could be abit convoluted) **WIP**
|
||||
|
||||
This defines a level in a world, it has 3 callback functions as parameters. These functions should
|
||||
|
||||
- define the setup logic
|
||||
- define the update (loop) logic (Used for actionbar mainly)
|
||||
- define the condition to pass the level
|
||||
- define the code to be run when the level is completed
|
||||
|
||||
> There is a a AbstractCondition class included with a BlockCondition. This (convoluted) way you can define a BlockCondition in the function that checks if the level is complete.
|
||||
|
||||
## Translations
|
||||
|
||||
Translations work with a resource pack. It's the same as with regular resource packs. The way it works with Pupeteer is to set a message to the screen but add the "%" prefix to the key.
|
||||
So `pupeteer.setActionbar("%foo.bar)` will look for the key `foo.bar` in the resource pack and display that message.
|
||||
|
||||
# Random knowlege
|
||||
|
||||
bunch of helper scripts for this [here](https://github.com/JaylyDev/ScriptAPI)
|
||||
This could be handy [jaylydb](https://github.com/JaylyDev/ScriptAPI/tree/stable/scripts/jaylydb)
|
||||
|
||||
# Authors
|
||||
|
||||
- [Bram Verhulst](https://github.com/brammie15) :p
|
||||
63
Setup.md
Normal file
63
Setup.md
Normal file
@@ -0,0 +1,63 @@
|
||||
# Setup
|
||||
|
||||
## Prerequisites
|
||||
|
||||
**Install Node.js tools, if you haven't already**
|
||||
|
||||
We're going to use the package manager [npm](https://www.npmjs.com/package/npm) to get more tools to make the process of building our project easier.
|
||||
|
||||
Visit [https://nodejs.org/](https://nodejs.org).
|
||||
|
||||
Download the version with "LTS" next to the number and install it. (LTS stands for Long Term Support, if you're curious.) In the Node.js Windows installer, accept the installation defaults. You do not need to install any additional tools for Native compilation.
|
||||
|
||||
**Install Visual Studio Code, if you haven't already**
|
||||
|
||||
Visit the [Visual Studio Code website](https://code.visualstudio.com) and install Visual Studio Code.
|
||||
|
||||
## Getting Started
|
||||
|
||||
1. Use npm to install our tools:
|
||||
|
||||
```powershell
|
||||
npm i
|
||||
```
|
||||
|
||||
1. When that's done, enter:
|
||||
|
||||
```powershell
|
||||
npm i gulp-cli --global
|
||||
```
|
||||
|
||||
It might also ask you to install the Minecraft Debugger and Blockception's Visual Studio Code plugin, which are plugins to Visual Studio Code that can help with Minecraft development. Go ahead and do that, if you haven't already.
|
||||
|
||||
# Running
|
||||
|
||||
To actually run the project, you must run `gulp` or `gulp watch` in the terminal.
|
||||
|
||||
# Gulpfile
|
||||
|
||||
At the top of the gulpfile there is a field for the name of the folder/project
|
||||
|
||||
# Manifest
|
||||
|
||||
In the behavior_packs folder change the name of the folder in that to match the name in the gulpfile.
|
||||
|
||||
In the same folder change the manifest.json to match your needs.
|
||||
|
||||
> `note`: this whole folder will be copied to the development_behavior_packs folder located at `%appdata%\Minecraft Education Edition\games\com.mojang\development_behavior_packs`
|
||||
|
||||
and if there is a resource_packs folder it will also be copied to the corresponding folder.
|
||||
|
||||
# World settings
|
||||
|
||||
Because education chose to be anoying (huge shock i know) you have to enable the js api manually through editing the world settings with nbt.
|
||||
|
||||
see a guide [here](https://wiki.bedrock.dev/nbt/experimental-education-edition.html)
|
||||
|
||||
# Debugging
|
||||
|
||||
To enable the conent log you have to enable the content log in the education settings.
|
||||
Open `%appdata%\Minecraft Education Edition\games\com.mojang\minecraftpe\options.txt` and change `content_log_file` and `content_log_gui` to `1`.
|
||||
Than ingame you can CTRL+H to open the content log.
|
||||
|
||||
> Note: it would be advised to change the keyboard settings because H defaults to show the tutorial witch can be anoying.
|
||||
0
behavior_packs/dialogue/scene.json
Normal file
0
behavior_packs/dialogue/scene.json
Normal file
33
behavior_packs/manifest.json
Normal file
33
behavior_packs/manifest.json
Normal file
@@ -0,0 +1,33 @@
|
||||
{
|
||||
"format_version": 2,
|
||||
"metadata": {
|
||||
"authors": ["Me and my cat"]
|
||||
},
|
||||
"header": {
|
||||
"name": "Reeks2Missie6BP",
|
||||
"description": "De behavior pack voor Reeks 2 Missie 6",
|
||||
"uuid": "868bf88f-78d9-4109-b1b2-308645e367bd",
|
||||
"version": [1, 0, 0],
|
||||
"min_engine_version": [1, 20, 0]
|
||||
},
|
||||
"modules": [
|
||||
{
|
||||
"description": "Script resources",
|
||||
"language": "javascript",
|
||||
"type": "script",
|
||||
"uuid": "20c42d36-9e2c-47e1-b710-8a8497f184dc",
|
||||
"version": [1, 0, 1],
|
||||
"entry": "scripts/main.js"
|
||||
}
|
||||
],
|
||||
"dependencies": [
|
||||
{
|
||||
"module_name": "@minecraft/server",
|
||||
"version": "1.4.0-beta"
|
||||
},
|
||||
{
|
||||
"uuid": "3c83eb6b-d574-411e-a430-f0e0ea816a3a",
|
||||
"version": [1, 0, 0]
|
||||
}
|
||||
]
|
||||
}
|
||||
BIN
behavior_packs/pack_icon.png
Normal file
BIN
behavior_packs/pack_icon.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 14 KiB |
564
gulpfile.js
Normal file
564
gulpfile.js
Normal file
@@ -0,0 +1,564 @@
|
||||
// === CONFIGURABLE VARIABLES
|
||||
|
||||
const bpfoldername = "Reeks2Missie6";
|
||||
const isStoreVersion = true;
|
||||
|
||||
const resource_pack_name = "Reeks2Missie6RP";
|
||||
const resource_pack_description = "De resource pack voor Reeks 2 Missie 6";
|
||||
const resource_pack_authors = ["Me and my cat"];
|
||||
|
||||
const behavior_pack_name = "Reeks2Missie6BP";
|
||||
const behavior_pack_description = "De behavior pack voor Reeks 2 Missie 6";
|
||||
const behavior_pack_authors = ["Me and my cat"];
|
||||
|
||||
// === Optional variables
|
||||
|
||||
const exportWorldFolderPath = "";
|
||||
|
||||
// === END CONFIGURABLE VARIABLES
|
||||
|
||||
const gulp = require("gulp");
|
||||
const ts = require("gulp-typescript");
|
||||
const del = require("del");
|
||||
const os = require("os");
|
||||
const spawn = require("child_process").spawn;
|
||||
const sourcemaps = require("gulp-sourcemaps");
|
||||
const zip = require("gulp-zip");
|
||||
const fs = require("fs");
|
||||
const rename = require("gulp-rename");
|
||||
const crypto = require("crypto");
|
||||
|
||||
var readLineSync = import("readline-sync");
|
||||
var NBT = import("nbtify");
|
||||
|
||||
const worldsFolderName = "minecraftWorlds";
|
||||
|
||||
const regularVersionMojangRoot = os.homedir() + "/appdata/Roaming/Minecraft Education Edition/games/com.mojang/";
|
||||
const storeVersionMojangRoot =
|
||||
os.homedir() +
|
||||
"/AppData/Local/Packages/Microsoft.MinecraftEducationEdition_8wekyb3d8bbwe/LocalState/games/com.mojang/";
|
||||
|
||||
const mcdir = isStoreVersion ? storeVersionMojangRoot : regularVersionMojangRoot;
|
||||
|
||||
function clean_build(callbackFunction) {
|
||||
del(["build/behavior_packs/", "build/resource_packs/"]).then(
|
||||
(value) => {
|
||||
callbackFunction(); // success
|
||||
},
|
||||
(reason) => {
|
||||
callbackFunction(); // error
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
function clean_export(cb) {
|
||||
del(["export/**/**"]).then(
|
||||
(value) => {
|
||||
cb(); // success
|
||||
},
|
||||
(reason) => {
|
||||
cb(); // error
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
function copy_behavior_packs() {
|
||||
return gulp.src(["behavior_packs/**/*"]).pipe(gulp.dest("build/behavior_packs"));
|
||||
}
|
||||
|
||||
function copy_resource_packs() {
|
||||
return gulp.src(["resource_packs/**/*"]).pipe(gulp.dest("build/resource_packs"));
|
||||
}
|
||||
|
||||
const copy_content = gulp.parallel(copy_behavior_packs, copy_resource_packs);
|
||||
|
||||
function compile_scripts() {
|
||||
return gulp
|
||||
.src("scripts/**/*.ts")
|
||||
.pipe(sourcemaps.init())
|
||||
.pipe(
|
||||
ts({
|
||||
module: "es2020",
|
||||
moduleResolution: "node",
|
||||
lib: ["es2020", "dom"],
|
||||
strict: true,
|
||||
target: "es2020",
|
||||
noImplicitAny: true,
|
||||
})
|
||||
)
|
||||
.pipe(
|
||||
sourcemaps.write("../../_" + bpfoldername + "Debug", {
|
||||
destPath: bpfoldername + "/scripts/",
|
||||
sourceRoot: "./../../../scripts/",
|
||||
})
|
||||
)
|
||||
.pipe(gulp.dest("build/behavior_packs/scripts"));
|
||||
}
|
||||
|
||||
const build = gulp.series(clean_build, copy_content, compile_scripts);
|
||||
|
||||
function clean_localmc(callbackFunction) {
|
||||
if (!bpfoldername || !bpfoldername.length || bpfoldername.length < 2) {
|
||||
console.log("No bpfoldername specified.");
|
||||
callbackFunction();
|
||||
return;
|
||||
}
|
||||
|
||||
del([mcdir + "development_behavior_packs/" + bpfoldername, mcdir + "development_resource_packs/" + bpfoldername], {
|
||||
force: true,
|
||||
}).then(
|
||||
(value) => {
|
||||
callbackFunction(); // Success
|
||||
},
|
||||
(reason) => {
|
||||
callbackFunction(); // Error
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
function deploy_localmc_behavior_packs() {
|
||||
console.log("Deploying to '" + mcdir + "development_behavior_packs/" + bpfoldername + "'");
|
||||
return gulp.src(["build/behavior_packs/**/*"]).pipe(gulp.dest(mcdir + "development_behavior_packs/" + bpfoldername));
|
||||
}
|
||||
|
||||
function deploy_localmc_resource_packs() {
|
||||
console.log("Deploying to '" + mcdir + "development_resource_packs/" + bpfoldername + "'");
|
||||
|
||||
return gulp.src(["build/resource_packs/**/*"]).pipe(gulp.dest(mcdir + "development_resource_packs/" + bpfoldername));
|
||||
}
|
||||
|
||||
function getTargetWorldPath() {
|
||||
return mcdir + worldsFolderName + "/" + activeWorldFolderName;
|
||||
}
|
||||
|
||||
function getTargetConfigPath() {
|
||||
return mcdir + "config";
|
||||
}
|
||||
|
||||
function getTargetWorldBackupPath() {
|
||||
return "backups/worlds/" + activeWorldFolderName;
|
||||
}
|
||||
|
||||
function getDevConfigPath() {
|
||||
return "config";
|
||||
}
|
||||
|
||||
function getDevWorldPath() {
|
||||
return "worlds/default";
|
||||
}
|
||||
|
||||
function getDevWorldBackupPath() {
|
||||
return "backups/worlds/devdefault";
|
||||
}
|
||||
|
||||
function clean_localmc_world(callbackFunction) {
|
||||
console.log("Removing '" + getTargetWorldPath() + "'");
|
||||
|
||||
del([getTargetWorldPath()], {
|
||||
force: true,
|
||||
}).then(
|
||||
(value) => {
|
||||
callbackFunction(); // Success
|
||||
},
|
||||
(reason) => {
|
||||
callbackFunction(); // Error
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
function clean_localmc_config(callbackFunction) {
|
||||
console.log("Removing '" + getTargetConfigPath() + "'");
|
||||
|
||||
del([getTargetConfigPath()], {
|
||||
force: true,
|
||||
}).then(
|
||||
(value) => {
|
||||
callbackFunction(); // Success
|
||||
},
|
||||
(reason) => {
|
||||
callbackFunction(); // Error
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
function clean_dev_world(callbackFunction) {
|
||||
console.log("Removing '" + getDevWorldPath() + "'");
|
||||
|
||||
del([getDevWorldPath()], {
|
||||
force: true,
|
||||
}).then(
|
||||
(value) => {
|
||||
callbackFunction(); // Success
|
||||
},
|
||||
(reason) => {
|
||||
callbackFunction(); // Error
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
function clean_localmc_world_backup(callbackFunction) {
|
||||
console.log("Removing backup'" + getTargetWorldBackupPath() + "'");
|
||||
|
||||
del([getTargetWorldBackupPath()], {
|
||||
force: true,
|
||||
}).then(
|
||||
(value) => {
|
||||
callbackFunction(); // Success
|
||||
},
|
||||
(reason) => {
|
||||
callbackFunction(); // Error
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
function clean_dev_world_backup(callbackFunction) {
|
||||
console.log("Removing backup'" + getDevWorldBackupPath() + "'");
|
||||
|
||||
del([getTargetWorldBackupPath()], {
|
||||
force: true,
|
||||
}).then(
|
||||
(value) => {
|
||||
callbackFunction(); // Success
|
||||
},
|
||||
(reason) => {
|
||||
callbackFunction(); // Error
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
function backup_dev_world() {
|
||||
console.log("Copying world '" + getDevWorldPath() + "' to '" + getDevWorldBackupPath() + "'");
|
||||
return gulp
|
||||
.src([getTargetWorldPath() + "/**/*"])
|
||||
.pipe(gulp.dest(getDevWorldBackupPath() + "/worlds/" + activeWorldFolderName));
|
||||
}
|
||||
|
||||
function deploy_localmc_config() {
|
||||
console.log("Copying world 'config/' to '" + getTargetConfigPath() + "'");
|
||||
return gulp.src([getDevConfigPath() + "/**/*"]).pipe(gulp.dest(getTargetConfigPath()));
|
||||
}
|
||||
|
||||
function deploy_localmc_world() {
|
||||
console.log("Copying world 'worlds/default/' to '" + getTargetWorldPath() + "'");
|
||||
return gulp.src([getDevWorldPath() + "/**/*"]).pipe(gulp.dest(getTargetWorldPath()));
|
||||
}
|
||||
|
||||
function ingest_localmc_world() {
|
||||
console.log("Ingesting world '" + getTargetWorldPath() + "' to '" + getDevWorldPath() + "'");
|
||||
return gulp.src([getTargetWorldPath() + "/**/*"]).pipe(gulp.dest(getDevWorldPath()));
|
||||
}
|
||||
|
||||
function backup_localmc_world() {
|
||||
console.log("Copying world '" + getTargetWorldPath() + "' to '" + getTargetWorldBackupPath() + "/'");
|
||||
return gulp
|
||||
.src([getTargetWorldPath() + "/**/*"])
|
||||
.pipe(gulp.dest(getTargetWorldBackupPath() + "/" + activeWorldFolderName));
|
||||
}
|
||||
|
||||
const deploy_localmc = gulp.series(
|
||||
clean_localmc,
|
||||
function (callbackFunction) {
|
||||
callbackFunction();
|
||||
},
|
||||
gulp.parallel(deploy_localmc_behavior_packs, deploy_localmc_resource_packs)
|
||||
);
|
||||
|
||||
function watch() {
|
||||
return gulp.watch(
|
||||
["scripts/**/*.ts", "behavior_packs/**/*", "resource_packs/**/*"],
|
||||
gulp.series(build, deploy_localmc)
|
||||
);
|
||||
}
|
||||
|
||||
function serve() {
|
||||
return gulp.watch(
|
||||
["scripts/**/*.ts", "behavior_packs/**/*", "resource_packs/**/*"],
|
||||
gulp.series(stopServer, build, deploy_localmc, startServer)
|
||||
);
|
||||
}
|
||||
|
||||
let activeServer = null;
|
||||
|
||||
function stopServer(callbackFunction) {
|
||||
if (activeServer) {
|
||||
activeServer.stdin.write("stop\n");
|
||||
activeServer = null;
|
||||
}
|
||||
|
||||
callbackFunction();
|
||||
}
|
||||
|
||||
function startServer(callbackFunction) {
|
||||
if (activeServer) {
|
||||
activeServer.stdin.write("stop\n");
|
||||
activeServer = null;
|
||||
}
|
||||
|
||||
activeServer = spawn(dedicatedServerPath + "bedrock_server");
|
||||
|
||||
let logBuffer = "";
|
||||
|
||||
let serverLogger = function (buffer) {
|
||||
let incomingBuffer = buffer.toString();
|
||||
|
||||
if (incomingBuffer.endsWith("\n")) {
|
||||
(logBuffer + incomingBuffer).split(/\n/).forEach(function (message) {
|
||||
if (message) {
|
||||
if (message.indexOf("Server started.") >= 0) {
|
||||
activeServer.stdin.write("script debugger listen 19144\n");
|
||||
}
|
||||
console.log("Server: " + message);
|
||||
}
|
||||
});
|
||||
logBuffer = "";
|
||||
} else {
|
||||
logBuffer += incomingBuffer;
|
||||
}
|
||||
};
|
||||
|
||||
activeServer.stdout.on("data", serverLogger);
|
||||
activeServer.stderr.on("data", serverLogger);
|
||||
|
||||
callbackFunction();
|
||||
}
|
||||
|
||||
hasZipped = false;
|
||||
|
||||
function rename_zip_to_mcworld(cb) {
|
||||
gulp
|
||||
.src(["export/export.zip"])
|
||||
.pipe(rename(bpfoldername + ".mcworld"))
|
||||
.pipe(gulp.dest("export/"));
|
||||
cb();
|
||||
}
|
||||
|
||||
function zip_world(cb) {
|
||||
let zip_path = "export/export.zip";
|
||||
console.log("export/" + bpfoldername + "/**/**");
|
||||
return gulp
|
||||
.src(["export/" + bpfoldername + "/**/**"], { base: "export/" + bpfoldername + "/" })
|
||||
.pipe(zip("export.zip", { compress: false, buffer: false }))
|
||||
.pipe(gulp.dest("export/"));
|
||||
}
|
||||
|
||||
function get_version() {
|
||||
let currentTimeStamp = new Date().toISOString().replace(/T/, " ").replace(/\..+/, "");
|
||||
return currentTimeStamp;
|
||||
}
|
||||
|
||||
function add_version_to_world_name(cb) {
|
||||
let worldNameFilePath = "export/" + bpfoldername + "/levelname.txt";
|
||||
let worldName = fs.readFileSync(worldNameFilePath, "utf8");
|
||||
currentTimeStamp = get_version();
|
||||
worldName = worldName + " " + currentTimeStamp;
|
||||
fs.writeFileSync(worldNameFilePath, worldName);
|
||||
console.log("Written " + worldName + " to " + worldNameFilePath);
|
||||
cb();
|
||||
}
|
||||
|
||||
function copy_build_resource_pack_to_export_folder(cb) {
|
||||
gulp
|
||||
.src(["build/resource_packs/**/**"])
|
||||
.pipe(gulp.dest("export/" + bpfoldername + "/resource_packs/" + bpfoldername));
|
||||
console.log(
|
||||
"Copied build/resource_packs/" +
|
||||
bpfoldername +
|
||||
"/**/** to export/" +
|
||||
bpfoldername +
|
||||
"/resource_packs/" +
|
||||
bpfoldername
|
||||
);
|
||||
cb();
|
||||
}
|
||||
|
||||
function copy_build_behavior_pack_to_export_folder(cb) {
|
||||
gulp
|
||||
.src(["build/behavior_packs/**/**"])
|
||||
.pipe(gulp.dest("export/" + bpfoldername + "/behavior_packs/" + bpfoldername));
|
||||
cb();
|
||||
}
|
||||
|
||||
function copy_world_to_export_folder(cb) {
|
||||
if (exportWorldFolderPath == "") {
|
||||
var readLineSync = import("readline-sync").then((readLineSync) => {
|
||||
let data = get_worlds_paths_and_names(cb);
|
||||
let index = readLineSync.keyInSelect(
|
||||
data.map((d) => d.name),
|
||||
"Which world do you want to copy?"
|
||||
);
|
||||
if (index === -1) {
|
||||
cb();
|
||||
return;
|
||||
}
|
||||
const world = data[index];
|
||||
//console.log("Copying world '" + world.path + "' to 'build/worlds/export/'");
|
||||
return gulp.src([world.path + "/**/*"]).pipe(gulp.dest("export/" + bpfoldername));
|
||||
});
|
||||
} else {
|
||||
return gulp.src([exportWorldFolderPath + "/**/*"]).pipe(gulp.dest("export/" + bpfoldername));
|
||||
}
|
||||
//copy the build to the correct folder
|
||||
cb();
|
||||
}
|
||||
|
||||
function get_worlds_paths_and_names(cb) {
|
||||
let data = [];
|
||||
const worldsPath = mcdir + worldsFolderName;
|
||||
const worlds = fs.readdirSync(worldsPath);
|
||||
worlds.forEach((world) => {
|
||||
let worldName = "UNDEFINED";
|
||||
try {
|
||||
worldName = fs.readFileSync(worldsPath + "/" + world + "/levelname.txt", "utf8");
|
||||
} catch (e) {
|
||||
console.log("Error reading levelname.txt for " + world);
|
||||
console.error(e);
|
||||
}
|
||||
data.push({
|
||||
path: worldsPath + "/" + world,
|
||||
name: worldName,
|
||||
});
|
||||
});
|
||||
cb();
|
||||
return data;
|
||||
}
|
||||
|
||||
async function nbt_rename_world(cb) {
|
||||
const NBT = await import("nbtify");
|
||||
const { readFile, writeFile } = await import("fs/promises");
|
||||
const buffer = await readFile("export/" + bpfoldername + "/level.dat");
|
||||
const data = await NBT.read(buffer);
|
||||
let oldLevelName = data.data.LevelName;
|
||||
let newName = bpfoldername + " " + get_version();
|
||||
data.data.LevelName = newName;
|
||||
const result = await NBT.write(data);
|
||||
await writeFile("export/" + bpfoldername + "/level.dat", result);
|
||||
console.log("Renamed " + oldLevelName + " to " + newName);
|
||||
cb();
|
||||
}
|
||||
|
||||
function levelnametxt_rename(cb) {
|
||||
const { readFile, writeFile } = import("fs/promises");
|
||||
const levelNameFilePath = "export/" + bpfoldername + "/levelname.txt";
|
||||
let levelName = fs.readFileSync(levelNameFilePath, "utf8");
|
||||
let newName = bpfoldername + " " + get_version();
|
||||
fs.writeFileSync(levelNameFilePath, newName);
|
||||
console.log("Renamed " + levelName + " to " + newName);
|
||||
cb();
|
||||
}
|
||||
|
||||
// Setup functions
|
||||
|
||||
function setup_behaviour_pack(cb) {
|
||||
const manifestPath = "behavior_packs/manifest.json";
|
||||
const manifest = JSON.parse(fs.readFileSync(manifestPath, "utf8"));
|
||||
|
||||
let header_uuid = get_behaviour_pack_uuid(cb);
|
||||
let module_uuid = generate_UUID(cb);
|
||||
let resource_pack_dependencies_uuid = get_resource_pack_uuid(cb);
|
||||
|
||||
console.log("Header UUID: " + header_uuid);
|
||||
console.log("Module UUID: " + module_uuid);
|
||||
|
||||
manifest.header.uuid = header_uuid;
|
||||
manifest.modules[0].uuid = module_uuid;
|
||||
manifest.dependencies[1].uuid = resource_pack_dependencies_uuid;
|
||||
|
||||
manifest.metadata.authors = behavior_pack_authors;
|
||||
manifest.header.name = behavior_pack_name;
|
||||
manifest.header.description = behavior_pack_description;
|
||||
|
||||
fs.writeFileSync(manifestPath, JSON.stringify(manifest, null, 1));
|
||||
cb();
|
||||
}
|
||||
function setup_resource_pack(cb) {
|
||||
const manifestPath = "resource_packs/manifest.json";
|
||||
const manifest = JSON.parse(fs.readFileSync(manifestPath, "utf8"));
|
||||
|
||||
let header_uuid = get_resource_pack_uuid(cb);
|
||||
let module_uuid = generate_UUID(cb);
|
||||
let dependencies_uuid = get_behaviour_pack_uuid(cb);
|
||||
|
||||
manifest.header.uuid = header_uuid;
|
||||
manifest.modules[0].uuid = module_uuid;
|
||||
manifest.dependencies[0].uuid = dependencies_uuid;
|
||||
|
||||
manifest.metadata.authors = resource_pack_authors;
|
||||
manifest.header.name = resource_pack_name;
|
||||
manifest.header.description = resource_pack_description;
|
||||
|
||||
fs.writeFileSync(manifestPath, JSON.stringify(manifest, null, 1));
|
||||
cb();
|
||||
}
|
||||
|
||||
function generate_UUID(cb) {
|
||||
let uuid = crypto.randomUUID();
|
||||
return uuid;
|
||||
}
|
||||
|
||||
var behavior_pack_uuid = null;
|
||||
var resource_pack_uuid = null;
|
||||
|
||||
function get_uuid_for_type(cb, type) {
|
||||
let to_return = null;
|
||||
switch (type) {
|
||||
case "behaviour_pack":
|
||||
if (behavior_pack_uuid === null) {
|
||||
behavior_pack_uuid = generate_UUID(cb);
|
||||
}
|
||||
to_return = behavior_pack_uuid;
|
||||
break;
|
||||
case "resource_pack":
|
||||
if (resource_pack_uuid === null) {
|
||||
resource_pack_uuid = generate_UUID(cb);
|
||||
}
|
||||
to_return = resource_pack_uuid;
|
||||
break;
|
||||
default:
|
||||
return generate_UUID(cb);
|
||||
}
|
||||
return to_return;
|
||||
}
|
||||
let get_behaviour_pack_uuid = (cb) => get_uuid_for_type(cb, "behaviour_pack");
|
||||
let get_resource_pack_uuid = (cb) => get_uuid_for_type(cb, "resource_pack");
|
||||
|
||||
exports.clean_build = clean_build;
|
||||
exports.copy_behavior_packs = copy_behavior_packs;
|
||||
exports.copy_resource_packs = copy_resource_packs;
|
||||
exports.compile_scripts = compile_scripts;
|
||||
exports.copy_content = copy_content;
|
||||
exports.build = build;
|
||||
exports.clean_localmc = clean_localmc;
|
||||
exports.deploy_localmc = deploy_localmc;
|
||||
exports.default = gulp.series(build, deploy_localmc);
|
||||
exports.clean = gulp.series(clean_build, clean_localmc);
|
||||
exports.watch = gulp.series(build, deploy_localmc, watch);
|
||||
exports.serve = gulp.series(build, deploy_localmc, startServer, serve);
|
||||
exports.updateworld = gulp.series(
|
||||
clean_localmc_world_backup,
|
||||
backup_localmc_world,
|
||||
clean_localmc_world,
|
||||
deploy_localmc_world
|
||||
);
|
||||
exports.ingestworld = gulp.series(clean_dev_world_backup, backup_dev_world, clean_dev_world, ingest_localmc_world);
|
||||
exports.updateconfig = gulp.series(clean_localmc_config, deploy_localmc_config);
|
||||
exports.compile_world = gulp.series(
|
||||
clean_export,
|
||||
build,
|
||||
copy_world_to_export_folder,
|
||||
gulp.parallel(copy_build_behavior_pack_to_export_folder, copy_build_resource_pack_to_export_folder),
|
||||
gulp.parallel(add_version_to_world_name, nbt_rename_world)
|
||||
);
|
||||
exports.zip = gulp.series(zip_world, rename_zip_to_mcworld);
|
||||
exports.export = gulp.series(
|
||||
clean_export,
|
||||
copy_world_to_export_folder,
|
||||
build,
|
||||
gulp.parallel(copy_build_behavior_pack_to_export_folder, copy_build_resource_pack_to_export_folder),
|
||||
levelnametxt_rename,
|
||||
nbt_rename_world,
|
||||
zip_world,
|
||||
rename_zip_to_mcworld
|
||||
);
|
||||
|
||||
exports.test = gulp.parallel(setup_behaviour_pack, setup_resource_pack);
|
||||
exports.export_clean = gulp.series(clean_export);
|
||||
524
old_readme.md
Normal file
524
old_readme.md
Normal file
@@ -0,0 +1,524 @@
|
||||
---
|
||||
page_type: sample
|
||||
author: mammerla
|
||||
description: A basic Hello World example of developing Minecraft scripts using TypeScript and a build process.
|
||||
ms.author: mikeam@microsoft.com
|
||||
ms.date: 04/01/2022
|
||||
languages:
|
||||
- typescript
|
||||
products:
|
||||
- minecraft
|
||||
---
|
||||
|
||||
# Minecraft TypeScript Starter Project
|
||||
|
||||
This sample demonstrates a simple build process and TypeScript compilation for Minecraft. This readme shows how you can use Betas APIs experiment to build out simple gameplay styles. You can use this project as a starter for your own scripting projects.
|
||||
|
||||
## Prerequisites
|
||||
|
||||
**Install Node.js tools, if you haven't already**
|
||||
|
||||
We're going to use the package manager [npm](https://www.npmjs.com/package/npm) to get more tools to make the process of building our project easier.
|
||||
|
||||
Visit [https://nodejs.org/](https://nodejs.org).
|
||||
|
||||
Download the version with "LTS" next to the number and install it. (LTS stands for Long Term Support, if you're curious.) In the Node.js Windows installer, accept the installation defaults. You do not need to install any additional tools for Native compilation.
|
||||
|
||||
**Install Visual Studio Code, if you haven't already**
|
||||
|
||||
Visit the [Visual Studio Code website](https://code.visualstudio.com) and install Visual Studio Code.
|
||||
|
||||
## Getting Started
|
||||
|
||||
1. To make your own environment look like the example, create a folder on your `C:\` drive and call it **projects**. Create a subfolder called **cotta**.
|
||||
|
||||
1. Put the extracted contents of the TypeScript Starter Project folder into **cotta**.
|
||||
|
||||
1. Open a Windows Terminal or PowerShell window and change the working directory to your **cotta** folder:
|
||||
|
||||
```powershell
|
||||
cd c:\projects\cotta\
|
||||
```
|
||||
|
||||
1. Use npm to install our tools:
|
||||
|
||||
```powershell
|
||||
npm i
|
||||
```
|
||||
|
||||
1. When that's done, enter:
|
||||
|
||||
```powershell
|
||||
npm i gulp-cli --global
|
||||
```
|
||||
|
||||
1. Use this shortcut command to open the project in Visual Studio Code:
|
||||
|
||||
```powershell
|
||||
code .
|
||||
```
|
||||
|
||||
It might also ask you to install the Minecraft Debugger and Blockception's Visual Studio Code plugin, which are plugins to Visual Studio Code that can help with Minecraft development. Go ahead and do that, if you haven't already.
|
||||
|
||||
### Chapter 1. Customize the behavior pack
|
||||
|
||||
In Visual Studio Code, expand the `behavior_packs` node in the treeview to the left, and rename the **cotta** folder to "cotta".
|
||||
|
||||
Use the Find/Replace command (Ctrl-Shift-F) to search for "cotta" and replace the instance in **gulpfile.js** and the instance in **launch.json** with "cotta."
|
||||
|
||||
Go back the Files tree view and open `behavior_packs\cotta\manifest.json`
|
||||
|
||||
Update the name and description properties to something like "Cotta Behavior Pack" and "My TypeScript Project".
|
||||
|
||||
Update the first and second UUID properties to make it unique to your project. See [this article](https://learn.microsoft.com/minecraft/creator/documents/behaviorpack) for tips on working with behavior packs and creating your own unique UUIDs.
|
||||
|
||||
> IMPORTANT:
|
||||
> You may also need to update the version of Beta APIs in your `dependencies` section to match your version of Minecraft.
|
||||
> Versions 1.19.40 feature `1.0.0-beta` APIs
|
||||
> Versions 1.19.50, 1.19.60, and 1.19.70 feature `1.1.0-beta` APIs
|
||||
> Versions 1.19.80 features `1.2.0-beta` APIs
|
||||
> Versions 1.20.0 features `1.3.0-beta` APIs
|
||||
> Versions 1.20.10 features `1.4.0-beta` APIs
|
||||
> Versions 1.20.20 features `1.5.0-beta` APIs
|
||||
> Future versions will likely require updated versions of Beta APIs.
|
||||
|
||||
### Chapter 2. Let's test the parts of our project
|
||||
|
||||
To get started, go into PowerShell and navigate to your **C:\projects\cotta** directory.
|
||||
Run this command:
|
||||
|
||||
```powershell
|
||||
Set-ExecutionPolicy -Scope Process -ExecutionPolicy Bypass
|
||||
```
|
||||
|
||||
Run this one, too.
|
||||
|
||||
```powershell
|
||||
gulp
|
||||
```
|
||||
|
||||
This uses a build tool called GulpJS and automatically compiles your TypeScript project and pushes it over into Minecraft.
|
||||
|
||||
You may hear a little tone through your speakers when it has successfully completed deployment.
|
||||
|
||||
Launch Minecraft and create a new world:
|
||||
|
||||
1. Call it **Cotta Test**.
|
||||
1. Select a Creative game mode.
|
||||
1. Select a Flat world option, under the Advanced section of the Create New World screen.
|
||||
1. Under Behavior Packs, under Available, you should see your Cotta Behavior Pack. Select it and Activate it.
|
||||
1. Enable the Beta APIs experiment toggle, under the Experiments section of the Create New World screen.
|
||||
1. Create the world and go into it.
|
||||
|
||||
Now you're in. Great!
|
||||
|
||||
By default, this starter pack comes with a simple script that will display a message:
|
||||
|
||||
`[Script Engine] Hello starter! Tick: <number>`
|
||||
|
||||
This means your behavior pack is working and your tools for compiling and pushing TypeScript are just fine. Awesome!
|
||||
|
||||
### Chapter 3. Scripting your gameplay
|
||||
|
||||
Let's go back to Visual Studio Code and change up some code.
|
||||
|
||||
Open up `scripts/main.ts` within Visual Studio Code.
|
||||
|
||||
#### Add some initialization code
|
||||
|
||||
Remove all the existing script code in **main.ts**. Replace it with this to start:
|
||||
|
||||
```typescript
|
||||
import {
|
||||
world,
|
||||
system,
|
||||
BlockPermutation,
|
||||
EntityInventoryComponent,
|
||||
ItemStack,
|
||||
DisplaySlotId,
|
||||
BlockType,
|
||||
BlockTypes,
|
||||
} from "@minecraft/server";
|
||||
|
||||
const START_TICK = 100;
|
||||
|
||||
// global variables
|
||||
let curTick = 0;
|
||||
|
||||
const ARENA_X_SIZE = 30;
|
||||
const ARENA_Z_SIZE = 30;
|
||||
const ARENA_X_OFFSET = 0;
|
||||
const ARENA_Y_OFFSET = -60;
|
||||
const ARENA_Z_OFFSET = 0;
|
||||
|
||||
function initializeBreakTheTerracotta() {
|
||||
const overworld = world.getDimension("overworld");
|
||||
|
||||
let scoreObjective = world.scoreboard.getObjective("score");
|
||||
|
||||
if (!scoreObjective) {
|
||||
scoreObjective = world.scoreboard.addObjective("score", "Level");
|
||||
}
|
||||
|
||||
// eliminate pesky nearby mobs
|
||||
let entities = overworld.getEntities({
|
||||
excludeTypes: ["player"],
|
||||
});
|
||||
|
||||
for (let entity of entities) {
|
||||
entity.kill();
|
||||
}
|
||||
|
||||
// set up scoreboard
|
||||
world.scoreboard.setObjectiveAtDisplaySlot(DisplaySlotId.Sidebar, {
|
||||
objective: scoreObjective,
|
||||
});
|
||||
|
||||
let players = world.getAllPlayers();
|
||||
|
||||
for (let player of players) {
|
||||
player.runCommand("scoreboard players set @s score 0");
|
||||
|
||||
let inv = player.getComponent("inventory") as EntityInventoryComponent;
|
||||
inv.container.addItem(new ItemStack("diamond_sword"));
|
||||
inv.container.addItem(new ItemStack("dirt", 64));
|
||||
|
||||
player.teleport(
|
||||
{
|
||||
x: ARENA_X_OFFSET - 3,
|
||||
y: ARENA_Y_OFFSET,
|
||||
z: ARENA_Z_OFFSET - 3,
|
||||
},
|
||||
{
|
||||
dimension: overworld,
|
||||
rotation: { x: 0, y: 0 }
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
world.sendMessage("BREAK THE TERRACOTTA");
|
||||
}
|
||||
|
||||
function gameTick() {
|
||||
try {
|
||||
curTick++;
|
||||
|
||||
if (curTick === START_TICK) {
|
||||
initializeBreakTheTerracotta();
|
||||
}
|
||||
} catch (e) {
|
||||
console.warn("Tick error: " + e);
|
||||
}
|
||||
|
||||
system.run(gameTick);
|
||||
}
|
||||
|
||||
system.run(gameTick);
|
||||
|
||||
```
|
||||
|
||||
This code does some work to initialize our gameplay for Minecraft by running several commands.
|
||||
|
||||
First, we queue up a run to our main tick function, gameTick. Note that at the end, we will requeue a game tick, which will run within the next tick frame. This will give us a callback that fires 20 times a second, and within this, we can put all of our game logic. We want the game to initialize some code; namely, the `initializeBreakTheTerracotta` function.
|
||||
|
||||
Note that we wait until `START_TICK` (100 ticks in) before the world is actually initialized. This gives Minecraft time to fully load up and get ready.
|
||||
|
||||
Within the initialize function, we run commands that:
|
||||
|
||||
- Clear out any existing mobs near the player in the world.
|
||||
- Set up a scoreboard objective for overall Level of the player, meaning the number of terracotta breaks they have
|
||||
- Give the current player a diamond sword and some dirty dirt
|
||||
- Use chat to give the player an instructional message
|
||||
|
||||
Now, let's run the code. This time, we're going to run gulp in "watch mode" - meaning it will just sit in the background and watch for changes, and if they happen, they will automatically compile and deploy to the Minecraft folder. This way, we won't have to worry about separately compiling every time we make a change to code.
|
||||
|
||||
Go back to your PowerShell window, and enter:
|
||||
|
||||
```powershell
|
||||
gulp watch
|
||||
```
|
||||
|
||||
You should see gulp compile and deploy to the Minecraft folder, and make a noise when it does that. From here, we don't need to tend to PowerShell except to see if there are any compilation errors down the road.
|
||||
|
||||
When you are done coding for the day, either hit **ctrl-c** in the PowerShell Window to stop the watch mode or close the window.
|
||||
|
||||
Now, let's go back to Minecraft.
|
||||
|
||||
Save and Quit to exit out of the world. We'll want to reload the world from here - any time you make a script change, you need to exit out of the world and reload it to see changes. Or, you can run the `/reload` command to reload the JavaScript files that have been deployed.
|
||||
|
||||
Now load the world. You should see your initialization changes: a new scoreboard, new items in your inventory, and a script message.
|
||||
|
||||
Note that as you work through this tutorial, we are going to run the initialization code more than once, so your player is going to get multiples of these items during this development and test phase. If that bothers you, feel free to toss out these items before you close the world.
|
||||
|
||||
#### Build your arena with some helper code
|
||||
|
||||
We're going to start by adding some handy helper utility code functions. This will show you how you can organize your code into separate modules or classes.
|
||||
|
||||
Add a new file to your `scripts` folder called `Utilities.ts`. Correct capitalization matters, so make sure the `U` is capitalized. Add the following code:
|
||||
|
||||
```typescript
|
||||
import { world, BlockType, BlockPermutation } from "@minecraft/server";
|
||||
|
||||
export default class Utilities {
|
||||
static fillBlock(
|
||||
blockType: BlockType,
|
||||
xFrom: number,
|
||||
yFrom: number,
|
||||
zFrom: number,
|
||||
xTo: number,
|
||||
yTo: number,
|
||||
zTo: number
|
||||
) {
|
||||
let overworld = world.getDimension("overworld");
|
||||
let perm = BlockPermutation.resolve(blockType.id);
|
||||
|
||||
for (let i = xFrom; i <= xTo; i++) {
|
||||
for (let j = yFrom; j <= yTo; j++) {
|
||||
for (let k = zFrom; k <= zTo; k++) {
|
||||
overworld.getBlock({ x: i, y: j, z: k })?.setPermutation(perm);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static fourWalls(
|
||||
blockType: BlockType,
|
||||
xFrom: number,
|
||||
yFrom: number,
|
||||
zFrom: number,
|
||||
xTo: number,
|
||||
yTo: number,
|
||||
zTo: number
|
||||
) {
|
||||
let overworld = world.getDimension("overworld");
|
||||
let perm = BlockPermutation.resolve(blockType.id);
|
||||
|
||||
for (let i = xFrom; i <= xTo; i++) {
|
||||
for (let k = yFrom; k <= yTo; k++) {
|
||||
overworld.getBlock({ x: i, y: k, z: zFrom })?.setPermutation(perm);
|
||||
overworld.getBlock({ x: i, y: k, z: zTo })?.setPermutation(perm);
|
||||
}
|
||||
}
|
||||
|
||||
for (let j = zFrom + 1; j < zTo; j++) {
|
||||
for (let k = yFrom; k <= yTo; k++) {
|
||||
overworld.getBlock({ x: xFrom, y: k, z:j })?.setPermutation(perm);
|
||||
overworld.getBlock({ x: xTo, y: k, z: j })?.setPermutation(perm);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
The first utility function here (`Utilities.fillBlock`) is relatively straightforward:
|
||||
|
||||
Across three dimensions (within three loops), it will basically set a block in the overworld to a particular type. This function just makes a big chunk of blocks.
|
||||
|
||||
The second utility function here (`Utilities.fourWalls`) basically creates a walled enclave. The first inner loop creates two stripes of blocks left to right (across X). The second inner loop creates two stripes of blocks south to north (across Z) - thus completing four walls that join each other.
|
||||
|
||||
Go back to **main.ts**. Let's use these functions in our initialization function.
|
||||
|
||||
First, we'll need an import function. Add a new line above `const START_TICK = 100;` and make this the second line of the file:
|
||||
|
||||
```typescript
|
||||
import Utilities from "./Utilities.js";
|
||||
```
|
||||
|
||||
Next, within `initializeBreakTheTerracotta`, let's add our arena initialization beneath the `world.sendMessage("BREAK THE TERRACOTTA!");` line of code:
|
||||
|
||||
```typescript
|
||||
let airBlockType = BlockTypes.get("minecraft:air");
|
||||
let cobblestoneBlockType = BlockTypes.get("minecraft:cobblestone");
|
||||
|
||||
if (airBlockType) {
|
||||
Utilities.fillBlock(
|
||||
airBlockType,
|
||||
ARENA_X_OFFSET - ARENA_X_SIZE / 2 + 1,
|
||||
ARENA_Y_OFFSET,
|
||||
ARENA_Z_OFFSET - ARENA_Z_SIZE / 2 + 1,
|
||||
ARENA_X_OFFSET + ARENA_X_SIZE / 2 - 1,
|
||||
ARENA_Y_OFFSET + 10,
|
||||
ARENA_Z_OFFSET + ARENA_Z_SIZE / 2 - 1
|
||||
);
|
||||
}
|
||||
|
||||
if (cobblestoneBlockType) {
|
||||
Utilities.fourWalls(
|
||||
cobblestoneBlockType,
|
||||
ARENA_X_OFFSET - ARENA_X_SIZE / 2,
|
||||
ARENA_Y_OFFSET,
|
||||
ARENA_Z_OFFSET - ARENA_Z_SIZE / 2,
|
||||
ARENA_X_OFFSET + ARENA_X_SIZE / 2,
|
||||
ARENA_Y_OFFSET + 10,
|
||||
ARENA_Z_OFFSET + ARENA_Z_SIZE / 2
|
||||
);
|
||||
}
|
||||
```
|
||||
|
||||
The first line just fills a cuboid with air - basically clearing out the arena of any previous items. The second line re-installs and adds four walls of cobblestone.
|
||||
|
||||
Exit out of your Minecraft world and restart it to load your changes. After a brief delay, you should find yourself in an arena.
|
||||
|
||||
Now, let's give ourselves some terracotta to break.
|
||||
|
||||
### Chapter 4. Add some gameplay basics - scoring and objectives
|
||||
|
||||
First, let's track some more game variables. Inside **main.ts**, add this directly beneath the `let curTick = 0` line of code:
|
||||
|
||||
```typescript
|
||||
let score = 0;
|
||||
let cottaX = 0;
|
||||
let cottaZ = 0;
|
||||
let spawnCountdown = 1;
|
||||
```
|
||||
|
||||
Add the following to the `gameTick` function, beneath the `curTick++` line of code:
|
||||
|
||||
```typescript
|
||||
if (curTick > START_TICK && curTick % 20 === 0) {
|
||||
let overworld = world.getDimension("overworld");
|
||||
|
||||
// no terracotta exists, and we're waiting to spawn a new one.
|
||||
if (spawnCountdown > 0) {
|
||||
spawnCountdown--;
|
||||
|
||||
if (spawnCountdown <= 0) {
|
||||
spawnNewTerracotta();
|
||||
}
|
||||
} else {
|
||||
checkForTerracotta();
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Now add the `spawnNewTerracotta()` and `checkForTerracotta()` functions after the last function and before the last `system.run(gameTick);` line of code:
|
||||
|
||||
```typescript
|
||||
function spawnNewTerracotta() {
|
||||
let overworld = world.getDimension("overworld");
|
||||
|
||||
// create new terracotta
|
||||
cottaX = Math.floor(Math.random() * (ARENA_X_SIZE - 1)) - (ARENA_X_SIZE / 2 - 1);
|
||||
cottaZ = Math.floor(Math.random() * (ARENA_Z_SIZE - 1)) - (ARENA_Z_SIZE / 2 - 1);
|
||||
|
||||
world.sendMessage("Creating new terracotta!");
|
||||
let block = overworld
|
||||
.getBlock({ x: cottaX + ARENA_X_OFFSET, y: 1 + ARENA_Y_OFFSET, z: cottaZ + ARENA_Z_OFFSET });
|
||||
|
||||
if (block) {
|
||||
block.setPermutation(BlockPermutation.resolve("minecraft:yellow_glazed_terracotta"));
|
||||
}
|
||||
}
|
||||
|
||||
function checkForTerracotta() {
|
||||
let overworld = world.getDimension("overworld");
|
||||
|
||||
let block = overworld.getBlock({ x: cottaX + ARENA_X_OFFSET, y: 1 + ARENA_Y_OFFSET, z: cottaZ + ARENA_Z_OFFSET });
|
||||
|
||||
if (block && !block.permutation.matches("minecraft:yellow_glazed_terracotta")) {
|
||||
// we didn't find the terracotta! set a new spawn countdown
|
||||
score++;
|
||||
spawnCountdown = 2;
|
||||
cottaX = -1;
|
||||
|
||||
let players = world.getAllPlayers();
|
||||
|
||||
for (let player of players) {
|
||||
player.runCommand("scoreboard players set @s score " + score);
|
||||
}
|
||||
|
||||
world.sendMessage("You broke the terracotta! Creating new terracotta in a few seconds.");
|
||||
cottaZ = -1;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Congratulations! You've just created a very basic and very easy game where you can run around and break terracotta with your sword.
|
||||
|
||||
To play, you will need to run the command `/gamemode s` to put Minecraft into survival mode so that you can break the terracotta.
|
||||
|
||||
After the terracotta is broken, your score will increment, and a new block is spawned.
|
||||
|
||||
#### Add a challenge - let's add some mobs
|
||||
|
||||
OK, let's add this function after the `checkForTerracotta()` function:
|
||||
|
||||
```typescript
|
||||
function spawnMobs() {
|
||||
let overworld = world.getDimension("overworld");
|
||||
|
||||
// spawn mobs = create 1-2 mobs
|
||||
let spawnMobCount = Math.floor(Math.random() * 2) + 1;
|
||||
|
||||
for (let j = 0; j < spawnMobCount; j++) {
|
||||
let zombieX = Math.floor(Math.random() * (ARENA_X_SIZE - 2)) - ARENA_X_SIZE / 2;
|
||||
let zombieZ = Math.floor(Math.random() * (ARENA_Z_SIZE - 2)) - ARENA_Z_SIZE / 2;
|
||||
|
||||
overworld.spawnEntity(
|
||||
"minecraft:zombie",
|
||||
{ x: zombieX + ARENA_X_OFFSET, y: 1 + ARENA_Y_OFFSET, z: zombieZ + ARENA_Z_OFFSET }
|
||||
);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
This function will spawn 1-2 zombies within the arena, at a random location. You can change the kinds of mobs to spawn, the number, and more within this function.
|
||||
|
||||
Let's call that function within our `gameTick` method:
|
||||
|
||||
```typescript
|
||||
let spawnInterval = Math.ceil(200 / ((score + 1) / 3));
|
||||
if (curTick > START_TICK && curTick % spawnInterval === 0) {
|
||||
spawnMobs();
|
||||
}
|
||||
```
|
||||
|
||||
For gameplay, we want mobs to spawn more frequently as your score goes up. To do this, the frequency at which `spawnMobs` is called depends on the `spawnInterval` variable. `spawnInterval` is the span of time between spawning new mobs. Because we divide this interval by our current score, this means that as our score goes up, the interval of time between spawning mobs gets shorter. This makes the challenge harder over time.
|
||||
|
||||
As you play, zombies should spawn and start chasing you. They'll spawn slowly at first, but as you break blocks they'll start to accumulate and bother you while you try to break terracotta blocks.
|
||||
|
||||
### Add more challenges!
|
||||
|
||||
Let's add a new gameplay twist: randomly spawning obstructions in the form of leaves.
|
||||
|
||||
Add this function to **main.ts** to randomly place some fuzzy leaves:
|
||||
|
||||
```typescript
|
||||
function addFuzzyLeaves() {
|
||||
let overworld = world.getDimension("overworld");
|
||||
|
||||
for (let i = 0; i < 10; i++) {
|
||||
const leafX = Math.floor(Math.random() * (ARENA_X_SIZE - 1)) - (ARENA_X_SIZE / 2 - 1);
|
||||
const leafY = Math.floor(Math.random() * 10);
|
||||
const leafZ = Math.floor(Math.random() * (ARENA_Z_SIZE - 1)) - (ARENA_Z_SIZE / 2 - 1);
|
||||
|
||||
overworld
|
||||
.getBlock({ x: leafX + ARENA_X_OFFSET, y: leafY + ARENA_Y_OFFSET, z: leafZ + ARENA_Z_OFFSET})
|
||||
?.setPermutation(BlockPermutation.resolve("minecraft:leaves"));
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
And call that function in your gameTick() function:
|
||||
|
||||
```typescript
|
||||
if (curTick > START_TICK && curTick % 29 === 0) {
|
||||
addFuzzyLeaves();
|
||||
}
|
||||
```
|
||||
|
||||
You may wonder why the interval here is 29. The main idea was to select a number to avoid the chance that on a particular tick we do everything at once (create new leaves, spawn mobs AND check terracotta state), so we try to have offset schedules for all of these different game activities.
|
||||
|
||||
Now exit out and reload your game. As you run around, you should see new leaves get spawned. This should add a little bit more challenge to your gameplay!
|
||||
|
||||
### Summary
|
||||
|
||||
With this starter, you've seen how to build a nice little arena game.
|
||||
|
||||
Like the randomly spawning leaves, you can see how you can add different gameplay elements into your arena. Maybe rather than leaves, you want to randomly generate some parkour platforms - or some treasures or weapons, or different types of mobs. Experiment and build your own custom competition arenas!
|
||||
|
||||
## Manifest
|
||||
|
||||
- [gulpfile.js](https://github.com/microsoft/minecraft-scripting-samples/blob/main/ts-starter/gulpfile.js): This file contains build instructions for Gulp, for building out TypeScript code.
|
||||
- [scripts](https://github.com/microsoft/minecraft-scripting-samples/blob/main/ts-starter/scripts): This contains all of your TypeScript files, that will be compiled and built into your projects.
|
||||
- [behavior_packs](https://github.com/microsoft/minecraft-scripting-samples/blob/main/ts-starter/behavior_packs): This contains resources and JSON files that define your behavior pack.
|
||||
9450
package-lock.json
generated
Normal file
9450
package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load Diff
29
package.json
Normal file
29
package.json
Normal file
@@ -0,0 +1,29 @@
|
||||
{
|
||||
"name": "scripting-starter",
|
||||
"version": "0.1.0",
|
||||
"productName": "Minecraft TypeScript Starter Project",
|
||||
"description": "Minecraft TypeScript Starter Project",
|
||||
"private": true,
|
||||
"devDependencies": {
|
||||
"@minecraft/server-ui": "^1.1.0",
|
||||
"del": "^6.0.0",
|
||||
"gulp": "^4.0.2",
|
||||
"gulp-cli": "^2.3.0",
|
||||
"gulp-rename": "^2.0.0",
|
||||
"gulp-sourcemaps": "^3.0.0",
|
||||
"gulp-typescript": "^6.0.0-alpha.1",
|
||||
"gulp-zip": "^5.1.0",
|
||||
"nbtify": "^1.85.0",
|
||||
"readline-sync": "^1.4.10",
|
||||
"source-map": "^0.7.4",
|
||||
"typescript": "^4.4.3"
|
||||
},
|
||||
"scripts": {
|
||||
"enablemcloopback": "CheckNetIsolation.exe LoopbackExempt -a -p=S-1-15-2-1958404141-86561845-1752920682-3514627264-368642714-62675701-733520436",
|
||||
"enablemcpreviewloopback": "CheckNetIsolation.exe LoopbackExempt -a -p=S-1-15-2-424268864-5579737-879501358-346833251-474568803-887069379-4040235476"
|
||||
},
|
||||
"dependencies": {
|
||||
"@minecraft/server": "1.4.0-beta.1.20.10-stable",
|
||||
"decode-uri-component": "^0.2.2"
|
||||
}
|
||||
}
|
||||
26
resource_packs/manifest.json
Normal file
26
resource_packs/manifest.json
Normal file
@@ -0,0 +1,26 @@
|
||||
{
|
||||
"format_version": 2,
|
||||
"metadata": {
|
||||
"authors": ["Me and my cat"]
|
||||
},
|
||||
"header": {
|
||||
"name": "Reeks2Missie6RP",
|
||||
"description": "De resource pack voor Reeks 2 Missie 6",
|
||||
"min_engine_version": [1, 20, 0],
|
||||
"uuid": "3c83eb6b-d574-411e-a430-f0e0ea816a3a",
|
||||
"version": [1, 0, 0]
|
||||
},
|
||||
"modules": [
|
||||
{
|
||||
"type": "resources",
|
||||
"uuid": "d563abd1-e684-42de-92f3-c9e08092609c",
|
||||
"version": [1, 0, 0]
|
||||
}
|
||||
],
|
||||
"dependencies": [
|
||||
{
|
||||
"uuid": "868bf88f-78d9-4109-b1b2-308645e367bd",
|
||||
"version": [1, 0, 0]
|
||||
}
|
||||
]
|
||||
}
|
||||
BIN
resource_packs/pack_icon.png
Normal file
BIN
resource_packs/pack_icon.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 14 KiB |
37
resource_packs/particles/point.json
Normal file
37
resource_packs/particles/point.json
Normal file
@@ -0,0 +1,37 @@
|
||||
{
|
||||
"format_version": "1.10.0",
|
||||
"particle_effect": {
|
||||
"description": {
|
||||
"identifier": "codecosmos:point",
|
||||
"basic_render_parameters": {
|
||||
"material": "particles_alpha",
|
||||
"texture": "textures/particle/point"
|
||||
}
|
||||
},
|
||||
"components": {
|
||||
"minecraft:emitter_rate_instant": {
|
||||
"num_particles": 1
|
||||
},
|
||||
"minecraft:emitter_lifetime_once": {
|
||||
"active_time": 1
|
||||
},
|
||||
"minecraft:emitter_shape_point": {},
|
||||
"minecraft:particle_lifetime_expression": {
|
||||
"max_lifetime": 0.1
|
||||
},
|
||||
"minecraft:particle_appearance_billboard": {
|
||||
"size": [0.25, 0.25],
|
||||
"facing_camera_mode": "rotate_xyz",
|
||||
"uv": {
|
||||
"texture_width": 16,
|
||||
"texture_height": 16,
|
||||
"uv": [0, 0],
|
||||
"uv_size": [16, 16]
|
||||
}
|
||||
},
|
||||
"minecraft:particle_appearance_tinting": {
|
||||
"color": ["variable.color.r ", "variable.color.g", "variable.color.b", 1]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
0
resource_packs/texts/en_US.lang
Normal file
0
resource_packs/texts/en_US.lang
Normal file
3
resource_packs/texts/languages.json
Normal file
3
resource_packs/texts/languages.json
Normal file
@@ -0,0 +1,3 @@
|
||||
[
|
||||
"en_US"
|
||||
]
|
||||
BIN
resource_packs/textures/blocks/redstone_lamp_off.png
Normal file
BIN
resource_packs/textures/blocks/redstone_lamp_off.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 107 B |
BIN
resource_packs/textures/blocks/redstone_lamp_on.png
Normal file
BIN
resource_packs/textures/blocks/redstone_lamp_on.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 107 B |
BIN
resource_packs/textures/particle/point.png
Normal file
BIN
resource_packs/textures/particle/point.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 168 B |
72
scripts/Commandeer/Makers/trailMaker.ts
Normal file
72
scripts/Commandeer/Makers/trailMaker.ts
Normal file
@@ -0,0 +1,72 @@
|
||||
import {
|
||||
Block,
|
||||
ChatSendAfterEvent,
|
||||
ItemStack,
|
||||
ItemUseOnBeforeEvent,
|
||||
MolangVariableMap,
|
||||
Player,
|
||||
world,
|
||||
} from "@minecraft/server";
|
||||
import { Vector3 } from "@minecraft/server";
|
||||
import { Vector3Add, Vector3ToString, vector3 } from "../utils/vectorUtils";
|
||||
import { spawnParticle } from "../utils/particleUtils";
|
||||
|
||||
export namespace TrailMaker {
|
||||
export class Maker {
|
||||
currentTrail: Trail;
|
||||
log: Map<string, number> = new Map();
|
||||
selectedIndex: number = 0;
|
||||
|
||||
OnChat(event: ChatSendAfterEvent) {}
|
||||
OnItemUse(event: ItemUseOnBeforeEvent) {
|
||||
const currentItemHeld: ItemStack = event.itemStack;
|
||||
const blockInteracted: Block = event.block;
|
||||
const player: Player = event.source as Player;
|
||||
const oldLog = this.log.get(player.name)!;
|
||||
this.log.set(player.name, Date.now());
|
||||
if (oldLog + 150 >= Date.now()) return;
|
||||
|
||||
if (event.itemStack.typeId == "minecraft:stick" && event.itemStack.nameTag == "AddPoint") {
|
||||
let pos = vector3(event.block.location.x, event.block.location.y, event.block.location.z);
|
||||
pos = Vector3Add(pos, vector3(0.5, 0, 0.5));
|
||||
pos = Vector3Add(pos, vector3(0, 1.1, 0));
|
||||
this.currentTrail.points.push(new Point(pos, this.currentTrail.currentPoint));
|
||||
//offset by half a block
|
||||
|
||||
this.currentTrail.currentPoint++;
|
||||
world.sendMessage(`Added point ${this.currentTrail.currentPoint}`);
|
||||
}
|
||||
}
|
||||
|
||||
Update() {
|
||||
this.currentTrail.points.forEach((point) => {
|
||||
spawnParticle(point.position, "minecraft:balloon_gas_particle", new MolangVariableMap());
|
||||
});
|
||||
}
|
||||
|
||||
Export() {}
|
||||
|
||||
constructor() {
|
||||
this.currentTrail = new Trail();
|
||||
}
|
||||
}
|
||||
|
||||
class Trail {
|
||||
points: Point[] = [];
|
||||
currentPoint: number = 0;
|
||||
nextParticleTimer: number = 0;
|
||||
currentParticleCounter: number = 0;
|
||||
|
||||
constructor() {}
|
||||
}
|
||||
|
||||
class Point {
|
||||
position: Vector3;
|
||||
index: number;
|
||||
|
||||
constructor(position: Vector3, index: number) {
|
||||
this.position = position;
|
||||
this.index = index;
|
||||
}
|
||||
}
|
||||
}
|
||||
13
scripts/Commandeer/Trigger/CCTrigger.ts
Normal file
13
scripts/Commandeer/Trigger/CCTrigger.ts
Normal file
@@ -0,0 +1,13 @@
|
||||
import { Trigger } from "./trigger";
|
||||
import { Maker } from "./maker";
|
||||
import { Manager } from "./manager";
|
||||
|
||||
export * from "./trigger";
|
||||
export * from "./maker";
|
||||
export * from "./manager";
|
||||
|
||||
export const CCTrigger = {
|
||||
Trigger,
|
||||
Maker,
|
||||
Manager,
|
||||
};
|
||||
199
scripts/Commandeer/Trigger/maker.ts
Normal file
199
scripts/Commandeer/Trigger/maker.ts
Normal file
@@ -0,0 +1,199 @@
|
||||
import { Trigger } from "./trigger";
|
||||
|
||||
import {
|
||||
Block,
|
||||
ChatSendAfterEvent,
|
||||
Color,
|
||||
EntityInventoryComponent,
|
||||
ItemStack,
|
||||
ItemUseOnBeforeEvent,
|
||||
MolangVariableMap,
|
||||
Player,
|
||||
Vector3,
|
||||
world,
|
||||
} from "@minecraft/server";
|
||||
import { vector3, vector3Distance } from "../utils/vectorUtils";
|
||||
import { Mindkeeper, StoreType } from "../mindKeeper";
|
||||
import { spawnParticle } from "../utils/particleUtils";
|
||||
import { Manager } from "./manager";
|
||||
|
||||
export class Maker {
|
||||
private manager: Manager;
|
||||
|
||||
log: Map<string, number> = new Map();
|
||||
|
||||
currentTrigger: Trigger | null = null;
|
||||
waitingForPoint2: boolean = false;
|
||||
point1: Vector3 = vector3(0, 0, 0);
|
||||
point2: Vector3 = vector3(0, 0, 0);
|
||||
|
||||
mindKeeper: Mindkeeper;
|
||||
|
||||
constructor(mindKeeper: Mindkeeper, manager: Manager) {
|
||||
this.mindKeeper = mindKeeper;
|
||||
this.manager = manager;
|
||||
}
|
||||
|
||||
OnChat(event: ChatSendAfterEvent) {
|
||||
if (event.message === "!toggleTriggers") {
|
||||
this.mindKeeper.set("ShowTriggers", (this.mindKeeper.get("ShowTriggers") as boolean) ? false : true);
|
||||
}
|
||||
if (event.message === "!TWand") {
|
||||
const item = new ItemStack("minecraft:stick");
|
||||
item.nameTag = "MakeTrigger";
|
||||
((event.sender as Player).getComponent("inventory") as EntityInventoryComponent).container.addItem(item);
|
||||
world.sendMessage("Thou shall have the Powah");
|
||||
}
|
||||
if (event.message === "!deleteCurrentTrigger") {
|
||||
let currentTriggerdTrigger = this.manager
|
||||
.GetTriggers()
|
||||
.filter((trigger) => trigger.IsPlayerInside(event.sender as Player));
|
||||
if (currentTriggerdTrigger.length > 0) {
|
||||
this.manager.GetTriggers().splice(this.manager.GetTriggers().indexOf(currentTriggerdTrigger[0]), 1);
|
||||
world.sendMessage("Trigger deleted");
|
||||
} else {
|
||||
world.sendMessage("No trigger to delete");
|
||||
}
|
||||
}
|
||||
const command = event.message.split(" ")[0];
|
||||
if (command == "!setFunction") {
|
||||
const name = event.message.split(" ")[1];
|
||||
const trigger = this.manager.GetCurrentActiveTriggers()[0];
|
||||
|
||||
if (trigger === undefined) {
|
||||
world.sendMessage("No trigger selected");
|
||||
return;
|
||||
}
|
||||
|
||||
trigger.eventToDispatch = name;
|
||||
this.manager.Save();
|
||||
world.sendMessage(`Function set to ${name}`);
|
||||
}
|
||||
}
|
||||
|
||||
OnItemUse(event: ItemUseOnBeforeEvent) {
|
||||
const currentItemHeld: ItemStack = event.itemStack;
|
||||
const blockInteracted: Block = event.block;
|
||||
const player: Player = event.source as Player;
|
||||
const oldLog = this.log.get(player.name)!;
|
||||
this.log.set(player.name, Date.now());
|
||||
if (oldLog + 150 >= Date.now()) return;
|
||||
|
||||
if (currentItemHeld.typeId == "minecraft:stick" && currentItemHeld.nameTag == "MakeTrigger") {
|
||||
if (this.waitingForPoint2) {
|
||||
this.point2 = vector3(blockInteracted.location.x, blockInteracted.location.y, blockInteracted.location.z);
|
||||
|
||||
let minX = Math.min(this.point1.x, this.point2.x);
|
||||
let maxX = Math.max(this.point1.x, this.point2.x) + 1;
|
||||
let minY = Math.min(this.point1.y, this.point2.y);
|
||||
let maxY = Math.max(this.point1.y, this.point2.y) + 1;
|
||||
let minZ = Math.min(this.point1.z, this.point2.z);
|
||||
let maxZ = Math.max(this.point1.z, this.point2.z) + 1;
|
||||
|
||||
//Take the outer bounds of the two points
|
||||
this.point1 = vector3(minX, minY, minZ);
|
||||
this.point2 = vector3(maxX, maxY, maxZ);
|
||||
|
||||
this.currentTrigger = new Trigger(this.point1, this.point2);
|
||||
|
||||
this.manager.AddTrigger(this.currentTrigger!);
|
||||
this.currentTrigger = null;
|
||||
this.waitingForPoint2 = false;
|
||||
world.sendMessage(`Trigger added`);
|
||||
this.manager.Save();
|
||||
return;
|
||||
} else {
|
||||
this.point1 = vector3(event.block.location.x, event.block.location.y, event.block.location.z);
|
||||
this.waitingForPoint2 = true;
|
||||
world.sendMessage(`Select a second point`);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
DrawLine(pos1: Vector3, pos2: Vector3, color: Color): void {
|
||||
if (pos1 != null && pos2 != null) {
|
||||
//draw a line with particles
|
||||
const xStep = pos2.x - pos1.x;
|
||||
const yStep = pos2.y - pos1.y;
|
||||
const zStep = pos2.z - pos1.z;
|
||||
|
||||
const steps = Math.max(Math.abs(xStep), Math.abs(yStep), Math.abs(zStep));
|
||||
for (let i = 0; i <= steps; i++) {
|
||||
const x = pos1.x + (xStep / steps) * i;
|
||||
const y = pos1.y + (yStep / steps) * i;
|
||||
const z = pos1.z + (zStep / steps) * i;
|
||||
|
||||
//make the ends and starts a different color
|
||||
let map = new MolangVariableMap();
|
||||
if (i == 0 || i == steps) {
|
||||
map = map.setColorRGB("variable.color", { red: 0, green: 255, blue: 0, alpha: 1.0 });
|
||||
const particleData = new MolangVariableMap().setColorRGB("variable.color", {
|
||||
red: 0,
|
||||
green: 1,
|
||||
blue: 0,
|
||||
alpha: 1,
|
||||
});
|
||||
spawnParticle(vector3(x, y + 0.1, z), "codecosmos:point", particleData);
|
||||
} else {
|
||||
const particleData = new MolangVariableMap().setColorRGB("variable.color", color);
|
||||
spawnParticle(vector3(x, y + 0.1, z), "codecosmos:point", particleData);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Update() {
|
||||
let shouldRender = this.mindKeeper.get("ShowTriggers") as boolean;
|
||||
this.manager.GetTriggers().forEach((trigger: Trigger) => {
|
||||
trigger.Update();
|
||||
|
||||
if (shouldRender) {
|
||||
const players = world.getAllPlayers();
|
||||
const triggerCenter = vector3(
|
||||
(trigger.point1.x + trigger.point2.x) / 2,
|
||||
(trigger.point1.y + trigger.point2.y) / 2,
|
||||
(trigger.point1.z + trigger.point2.z) / 2
|
||||
);
|
||||
const distnaces = players.map((player) => {
|
||||
return {
|
||||
player: player,
|
||||
distance: vector3Distance(player.location, triggerCenter),
|
||||
};
|
||||
});
|
||||
|
||||
distnaces.sort((a, b) => a.distance - b.distance);
|
||||
const closestPlayer = distnaces[0].player;
|
||||
const distance = distnaces[0].distance;
|
||||
|
||||
if (distance > 25) return;
|
||||
|
||||
const p1 = trigger.point1;
|
||||
const p2 = vector3(trigger.point1.x, trigger.point2.y, trigger.point1.z);
|
||||
const p3 = vector3(trigger.point2.x, trigger.point1.y, trigger.point1.z);
|
||||
const p4 = vector3(trigger.point2.x, trigger.point2.y, trigger.point1.z);
|
||||
const p5 = vector3(trigger.point1.x, trigger.point1.y, trigger.point2.z);
|
||||
const p6 = vector3(trigger.point1.x, trigger.point2.y, trigger.point2.z);
|
||||
const p7 = vector3(trigger.point2.x, trigger.point1.y, trigger.point2.z);
|
||||
const p8 = trigger.point2;
|
||||
|
||||
//is there a player inside this trigger
|
||||
const color = trigger.IsAnyPlayerInside()
|
||||
? { red: 1, green: 0, blue: 0, alpha: 1.0 }
|
||||
: { red: 1, green: 1, blue: 1, alpha: 1.0 };
|
||||
|
||||
this.DrawLine(p1, p2, color);
|
||||
this.DrawLine(p2, p4, color);
|
||||
this.DrawLine(p4, p3, color);
|
||||
this.DrawLine(p3, p1, color);
|
||||
this.DrawLine(p5, p6, color);
|
||||
this.DrawLine(p6, p8, color);
|
||||
this.DrawLine(p8, p7, color);
|
||||
this.DrawLine(p7, p5, color);
|
||||
this.DrawLine(p1, p5, color);
|
||||
this.DrawLine(p2, p6, color);
|
||||
this.DrawLine(p3, p7, color);
|
||||
this.DrawLine(p4, p8, color);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
117
scripts/Commandeer/Trigger/manager.ts
Normal file
117
scripts/Commandeer/Trigger/manager.ts
Normal file
@@ -0,0 +1,117 @@
|
||||
import { ChatSendAfterEvent, ItemUseOnBeforeEvent, Player, system, world } from "@minecraft/server";
|
||||
import { Mindkeeper, StoreType } from "../mindKeeper";
|
||||
import { vector3 } from "../utils/vectorUtils";
|
||||
import { Maker } from "./maker";
|
||||
import { Trigger } from "./trigger";
|
||||
|
||||
export class TriggerEvent {
|
||||
player: Player;
|
||||
trigger: Trigger;
|
||||
|
||||
constructor(player: Player, trigger: Trigger) {
|
||||
this.player = player;
|
||||
this.trigger = trigger;
|
||||
}
|
||||
}
|
||||
|
||||
export type TriggerEventHandler = (event: TriggerEvent) => void;
|
||||
|
||||
export class Manager {
|
||||
private triggers: Trigger[] = [];
|
||||
private functionTriggers: Map<string, TriggerEventHandler> = new Map();
|
||||
private mindKeeper: Mindkeeper;
|
||||
private maker: Maker;
|
||||
|
||||
constructor(mindKeeper: Mindkeeper) {
|
||||
this.mindKeeper = mindKeeper;
|
||||
this.maker = new Maker(mindKeeper, this);
|
||||
}
|
||||
|
||||
RegisterStores() {
|
||||
this.mindKeeper.registerStore("triggers", StoreType.string);
|
||||
this.mindKeeper.registerStore("ShowTriggers", StoreType.boolean);
|
||||
}
|
||||
|
||||
OnItemUse(event: ItemUseOnBeforeEvent) {
|
||||
this.maker.OnItemUse(event);
|
||||
}
|
||||
|
||||
OnChat(event: ChatSendAfterEvent) {
|
||||
this.maker.OnChat(event);
|
||||
}
|
||||
//the func should have a TriggerEvent as a parameter
|
||||
RegisterFunctionTrigger(name: string, func: TriggerEventHandler) {
|
||||
this.functionTriggers.set(name, func);
|
||||
}
|
||||
|
||||
//#region Loading / Saving
|
||||
|
||||
Load() {
|
||||
this.LoadTriggers();
|
||||
}
|
||||
|
||||
Save() {
|
||||
this.SaveTriggers();
|
||||
}
|
||||
|
||||
private LoadTriggers() {
|
||||
const triggers = this.mindKeeper.get("triggers") as string;
|
||||
if (triggers === undefined) return;
|
||||
|
||||
const data = JSON.parse(triggers);
|
||||
data.forEach((trigger: any) => {
|
||||
let point1 = vector3(trigger.point1.x, trigger.point1.y, trigger.point1.z);
|
||||
let point2 = vector3(trigger.point2.x, trigger.point2.y, trigger.point2.z);
|
||||
let eventToDispatch = trigger.eventToDispatch;
|
||||
|
||||
let newTrigger = new Trigger(point1, point2);
|
||||
newTrigger.eventToDispatch = eventToDispatch;
|
||||
|
||||
this.triggers.push(newTrigger);
|
||||
});
|
||||
}
|
||||
|
||||
private SaveTriggers() {
|
||||
this.mindKeeper.set("triggers", JSON.stringify(this.triggers));
|
||||
}
|
||||
|
||||
//#endregion
|
||||
|
||||
AddTrigger(trigger: Trigger) {
|
||||
this.triggers.push(trigger);
|
||||
}
|
||||
|
||||
GetCurrentActiveTriggers(): Trigger[] {
|
||||
return this.triggers.filter((trigger) => trigger.IsAnyPlayerInside());
|
||||
}
|
||||
|
||||
Update() {
|
||||
const players = world.getAllPlayers();
|
||||
|
||||
this.maker.Update();
|
||||
this.triggers.forEach((trigger: Trigger) => {
|
||||
trigger.Update();
|
||||
|
||||
players.forEach((player) => {
|
||||
// player.sendMessage(`Player ${player.name} is in trigger ${trigger.IsPlayerInside(player)}`);
|
||||
if (trigger.hasPlayerEnterdTrigger(player)) {
|
||||
world.sendMessage(`Player ${player.name} entered trigger`);
|
||||
//Check if a function trigger is set
|
||||
const isFunctionSet = this.functionTriggers.has(trigger.eventToDispatch);
|
||||
|
||||
if (isFunctionSet) {
|
||||
const event = new TriggerEvent(player, trigger);
|
||||
|
||||
this.functionTriggers.get(trigger.eventToDispatch)!(event);
|
||||
} else {
|
||||
world.sendMessage(`Triggered ${trigger.eventToDispatch}`);
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
GetTriggers(): Trigger[] {
|
||||
return this.triggers;
|
||||
}
|
||||
}
|
||||
82
scripts/Commandeer/Trigger/trigger.ts
Normal file
82
scripts/Commandeer/Trigger/trigger.ts
Normal file
@@ -0,0 +1,82 @@
|
||||
import { Player, Vector3, world } from "@minecraft/server";
|
||||
import { vector3 } from "../utils/vectorUtils";
|
||||
|
||||
export class Trigger {
|
||||
point1: Vector3 = vector3(0, 0, 0);
|
||||
point2: Vector3 = vector3(0, 0, 0);
|
||||
eventToDispatch: string = "";
|
||||
|
||||
isPlayerInTrigger: Map<string, boolean> = new Map();
|
||||
|
||||
hasTriggerd: boolean = false;
|
||||
|
||||
constructor(point1: Vector3, point2: Vector3) {
|
||||
this.point1 = point1;
|
||||
this.point2 = point2;
|
||||
}
|
||||
|
||||
hasPlayerEnterdTrigger(player: Player): boolean {
|
||||
const minX = Math.min(this.point1.x, this.point2.x);
|
||||
const maxX = Math.max(this.point1.x, this.point2.x);
|
||||
const minY = Math.min(this.point1.y, this.point2.y);
|
||||
const maxY = Math.max(this.point1.y, this.point2.y);
|
||||
const minZ = Math.min(this.point1.z, this.point2.z);
|
||||
const maxZ = Math.max(this.point1.z, this.point2.z);
|
||||
|
||||
const playerPos = player.location;
|
||||
|
||||
const inside =
|
||||
playerPos.x >= minX &&
|
||||
playerPos.x <= maxX &&
|
||||
playerPos.y >= minY &&
|
||||
playerPos.y + 1 <= maxY &&
|
||||
playerPos.z >= minZ &&
|
||||
playerPos.z <= maxZ;
|
||||
|
||||
let entererdTrigger = false;
|
||||
if (!this.isPlayerInTrigger.get(player.name) && inside) {
|
||||
entererdTrigger = true;
|
||||
}
|
||||
|
||||
this.isPlayerInTrigger.set(player.name, inside);
|
||||
|
||||
return entererdTrigger;
|
||||
}
|
||||
|
||||
IsPlayerInside(player: Player): boolean {
|
||||
return this.isPlayerInTrigger.get(player.name) || false;
|
||||
}
|
||||
|
||||
IsAnyPlayerInside(): boolean {
|
||||
let isInside = false;
|
||||
world.getAllPlayers().forEach((player) => {
|
||||
if (this.isPlayerInTrigger.get(player.name)) {
|
||||
isInside = true;
|
||||
}
|
||||
});
|
||||
return isInside;
|
||||
}
|
||||
|
||||
ShouldTrigger(): boolean {
|
||||
let isSomethingInTrigger = false;
|
||||
const players = world.getAllPlayers();
|
||||
players.forEach((player) => {
|
||||
if (this.hasPlayerEnterdTrigger(player)) {
|
||||
isSomethingInTrigger = true;
|
||||
}
|
||||
});
|
||||
return isSomethingInTrigger;
|
||||
}
|
||||
|
||||
Update() {
|
||||
world
|
||||
.getDimension("overworld")
|
||||
.getEntities({ type: "minecraft:player" })
|
||||
.forEach((player) => {
|
||||
//Check if the distance between the player and the trigger is less than the width of the trigger
|
||||
// if (this.hasPlayerEnterdTrigger(player.location)) {
|
||||
// world.sendMessage(`Player ${player.nameTag} is in trigger`);
|
||||
// }
|
||||
});
|
||||
}
|
||||
}
|
||||
99
scripts/Commandeer/command/command.ts
Normal file
99
scripts/Commandeer/command/command.ts
Normal file
@@ -0,0 +1,99 @@
|
||||
import { CommandResult, Dimension, Entity, world, Player } from "@minecraft/server";
|
||||
|
||||
export class Command {
|
||||
private __player: Player;
|
||||
public argv: IterableIterator<string>;
|
||||
public get player(): Player {
|
||||
return this.__player;
|
||||
}
|
||||
public get argv0(): string {
|
||||
return this.argv.next().value;
|
||||
}
|
||||
constructor(argv: string[], player: Player) {
|
||||
this.argv = (function* () {
|
||||
for (let arg of argv) yield arg;
|
||||
})();
|
||||
this.__player = player;
|
||||
}
|
||||
}
|
||||
|
||||
export class Commands {
|
||||
/**
|
||||
* @remarks
|
||||
* Runs a particular command synchronously from the context.
|
||||
* @param commandString
|
||||
* Command to run. Note that command strings should not start
|
||||
* with slash.
|
||||
* @param target
|
||||
* Target to be used as context for the command to run
|
||||
* within.
|
||||
* @returns
|
||||
* For commands that return data, returns a CommandResult with
|
||||
* an indicator of command results.
|
||||
* @throws This function can throw errors.
|
||||
*/
|
||||
static run(commandString: string, target: Dimension | Entity = world.getDimension("overworld")): CommandResult {
|
||||
if (target instanceof Dimension || Entity) return target.runCommand(commandString);
|
||||
else throw TypeError("Native type conversion failed");
|
||||
}
|
||||
/**
|
||||
* @remarks
|
||||
* Runs a particular command asynchronously from the context.
|
||||
* Where possible - and especially for
|
||||
* long-running operations - you should use runCommandAsync
|
||||
* over runCommand.
|
||||
* @param commandString
|
||||
* Command to run. Note that command strings should not start
|
||||
* with slash.
|
||||
* @param target
|
||||
* Target to be used as context for the command to run
|
||||
* within.
|
||||
* @returns
|
||||
* For commands that return data, returns a CommandResult with
|
||||
* an indicator of command results.
|
||||
* @throws This function can throw errors.
|
||||
*/
|
||||
static async runAsync(
|
||||
commandString: string,
|
||||
target: Dimension | Entity = world.getDimension("overworld")
|
||||
): Promise<CommandResult> {
|
||||
if (target instanceof Dimension || Entity) return await target.runCommandAsync(commandString);
|
||||
else throw TypeError("Native type conversion failed");
|
||||
}
|
||||
|
||||
/**
|
||||
* @remarks
|
||||
* Registers a new custom command. This command will become
|
||||
* available in Minecraft via [prefix][command].
|
||||
* @param prefix
|
||||
* The prefix of this specific command. (Case sensitive)
|
||||
* @param command
|
||||
* Name of this specific command. (Case sensitive)
|
||||
* @param commandFunction
|
||||
* Implementation of the command function.
|
||||
* @throws
|
||||
* This function can throw error: You are not allow to register a new slash command.
|
||||
* @example example1.js
|
||||
* ```typescript
|
||||
* Commands.register("!", "test", function (arg) {
|
||||
* arg.player.runCommandAsync(`say ${arg.argv0} ${JSON.stringify([...arg.argv])}`);
|
||||
* });
|
||||
* ```
|
||||
*/
|
||||
public static register(prefix: string, command: string, commandFunction: (arg: Command) => void): void {
|
||||
if (prefix.startsWith("/")) throw Error("Unable to register slash commands.");
|
||||
world.beforeEvents.chatSend.subscribe((arg) => {
|
||||
var argv = arg.message.split(/(".*?"|[^"\s]+)+(?=\s*|\s*$)/g).filter((e) => e.trim().length > 0);
|
||||
if (argv[0] === `${prefix}${command}`) {
|
||||
arg.cancel = true;
|
||||
try {
|
||||
commandFunction(new Command(argv, arg.sender));
|
||||
} catch (err) {
|
||||
let { statusMessage } = JSON.parse(err as string);
|
||||
console.error(err);
|
||||
arg.sender.sendMessage(`§c${statusMessage}`);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
abstract class AbstractLevelCondition {
|
||||
constructor() {}
|
||||
|
||||
abstract checkCondition(): boolean;
|
||||
}
|
||||
|
||||
export default AbstractLevelCondition;
|
||||
|
||||
//Interface could be better
|
||||
24
scripts/Commandeer/completionCondition/BlockCondition.ts
Normal file
24
scripts/Commandeer/completionCondition/BlockCondition.ts
Normal file
@@ -0,0 +1,24 @@
|
||||
import { BlockType, Vector3, world } from "@minecraft/server";
|
||||
import AbstractLevelCondition from "./AbstractCondition";
|
||||
import { Vector3ToString } from "../utils/vectorUtils";
|
||||
|
||||
class BlockCondition extends AbstractLevelCondition {
|
||||
position: Vector3;
|
||||
blockType: BlockType;
|
||||
|
||||
constructor(position: Vector3, blockType: BlockType) {
|
||||
super();
|
||||
this.position = position;
|
||||
this.blockType = blockType;
|
||||
}
|
||||
|
||||
checkCondition(): boolean {
|
||||
const block = world.getDimension("overworld").getBlock(this.position);
|
||||
if (!block) {
|
||||
return false;
|
||||
}
|
||||
return block.typeId === this.blockType.id;
|
||||
}
|
||||
}
|
||||
|
||||
export default BlockCondition;
|
||||
@@ -0,0 +1,21 @@
|
||||
import { BlockType, Vector3, world } from "@minecraft/server";
|
||||
import AbstractLevelCondition from "./AbstractCondition";
|
||||
|
||||
class ButtonPushCondition extends AbstractLevelCondition {
|
||||
position: Vector3;
|
||||
|
||||
constructor(position: Vector3) {
|
||||
super();
|
||||
this.position = position;
|
||||
}
|
||||
|
||||
checkCondition(): boolean {
|
||||
const button = world.getDimension("overworld").getBlock(this.position);
|
||||
if (!button || !button.getRedstonePower()) {
|
||||
return false;
|
||||
}
|
||||
return button.getRedstonePower()! > 0;
|
||||
}
|
||||
}
|
||||
|
||||
export default ButtonPushCondition;
|
||||
48
scripts/Commandeer/level/level.ts
Normal file
48
scripts/Commandeer/level/level.ts
Normal file
@@ -0,0 +1,48 @@
|
||||
import { World } from "@minecraft/server";
|
||||
|
||||
class Level {
|
||||
levelCompleteCallback: Function;
|
||||
levelCheckCallback: Function;
|
||||
levelSetupCallback: Function;
|
||||
levelUpdateCallback: Function;
|
||||
isCompleted: boolean = false;
|
||||
isSetup: boolean = false;
|
||||
|
||||
constructor(
|
||||
levelSetupCallback: Function,
|
||||
levelUpdateCallback: Function,
|
||||
levelCompleteCallback: Function,
|
||||
levelCheckCallback: Function
|
||||
) {
|
||||
this.levelSetupCallback = levelSetupCallback;
|
||||
this.levelCompleteCallback = levelCompleteCallback;
|
||||
this.levelCheckCallback = levelCheckCallback;
|
||||
this.levelUpdateCallback = levelUpdateCallback;
|
||||
}
|
||||
|
||||
setup() {
|
||||
this.levelSetupCallback();
|
||||
}
|
||||
|
||||
update() {
|
||||
if (!this.isSetup) {
|
||||
this.setup();
|
||||
this.isSetup = true;
|
||||
}
|
||||
this.levelUpdateCallback();
|
||||
if (this.levelCheckCallback() && !this.isCompleted) {
|
||||
this.levelCompleteCallback();
|
||||
this.isCompleted = true;
|
||||
}
|
||||
}
|
||||
|
||||
reset() {
|
||||
this.isCompleted = false;
|
||||
}
|
||||
}
|
||||
|
||||
//nextlevel
|
||||
//mindkeeper
|
||||
//pupeteer
|
||||
|
||||
export default Level;
|
||||
44
scripts/Commandeer/level/levelTypes.ts
Normal file
44
scripts/Commandeer/level/levelTypes.ts
Normal file
@@ -0,0 +1,44 @@
|
||||
import { BlockType, MinecraftBlockTypes, Vector3, World } from "@minecraft/server";
|
||||
|
||||
export type blockCondition = {
|
||||
block: BlockType;
|
||||
position: Vector3;
|
||||
};
|
||||
|
||||
/**
|
||||
* Checks if there is a lever at the specified position in the world.
|
||||
*
|
||||
* @param world - The world object.
|
||||
* @param position - The position of the lever.
|
||||
* @returns Returns true if there is a lever at the specified position and it has a redstone power of 15, otherwise returns false.
|
||||
* @throws Throws an error if there is no lever at the specified position.
|
||||
*/
|
||||
export function leverOn(world: World, position: Vector3): boolean {
|
||||
let lever = world.getDimension("overworld").getBlock(position);
|
||||
if (!(lever?.typeId == "minecraft:lever")) {
|
||||
throw new Error(`No lever at ${position}`);
|
||||
}
|
||||
return lever.getRedstonePower() == 15;
|
||||
}
|
||||
|
||||
export type LeverCondition = {
|
||||
position: Vector3;
|
||||
state: boolean;
|
||||
};
|
||||
|
||||
export type LevelBlockCondition = {
|
||||
conditions: blockCondition[];
|
||||
};
|
||||
|
||||
export type LevelLeverCondition = {
|
||||
conditions: LeverCondition[];
|
||||
};
|
||||
|
||||
export type AgentNoGoZone = {
|
||||
//Reason for needing to use is because the Agent can't be queried for its location in minecraft
|
||||
position: Vector3;
|
||||
};
|
||||
|
||||
export type LevelNoGoZone = {
|
||||
zones: AgentNoGoZone[];
|
||||
};
|
||||
230
scripts/Commandeer/mindKeeper.ts
Normal file
230
scripts/Commandeer/mindKeeper.ts
Normal file
@@ -0,0 +1,230 @@
|
||||
import { ChatSendAfterEvent, DynamicPropertiesDefinition, PropertyRegistry, World, system } from "@minecraft/server";
|
||||
|
||||
class Store {
|
||||
type: StoreType;
|
||||
name: string;
|
||||
|
||||
constructor(type: StoreType, name: string) {
|
||||
this.type = type;
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
getType(): StoreType {
|
||||
return this.type;
|
||||
}
|
||||
|
||||
getName(): string {
|
||||
return this.name;
|
||||
}
|
||||
}
|
||||
|
||||
enum StoreType {
|
||||
string = "string",
|
||||
number = "number",
|
||||
boolean = "boolean",
|
||||
}
|
||||
|
||||
/**
|
||||
* Represents a Mindkeeper, responsible for managing stores and dynamic properties in a world.
|
||||
*/
|
||||
class Mindkeeper {
|
||||
registerdStores: Array<Store> = [];
|
||||
propertyManager = new DynamicPropertiesDefinition();
|
||||
world: World;
|
||||
initialised: boolean = false;
|
||||
debugLog: string[] = [];
|
||||
|
||||
/**
|
||||
* Creates a new instance of Mindkeeper.
|
||||
* @param world The world associated with the Mindkeeper.
|
||||
*/
|
||||
constructor(world: World) {
|
||||
this.world = world;
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers a store with the specified name and type.
|
||||
* @param store The name of the store.
|
||||
* @param type The type of the store.
|
||||
*/
|
||||
registerStore(store: string, type: StoreType): void {
|
||||
this.registerdStores.push(new Store(type, store));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an array of registered stores.
|
||||
* @returns An array of registered stores.
|
||||
*/
|
||||
getStores() {
|
||||
return this.registerdStores;
|
||||
}
|
||||
|
||||
/**
|
||||
* Prints the debug log by sending each log entry as a message to the world.
|
||||
*/
|
||||
printDebug() {
|
||||
this.debugLog.forEach((t) => {
|
||||
this.world.sendMessage(t);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers the dynamic properties to the world's property registry.
|
||||
* @param propertyRegistry The property registry of the world.
|
||||
*/
|
||||
registerToWorld(propertyRegistry: PropertyRegistry) {
|
||||
for (let i = 0; i < this.registerdStores.length; i++) {
|
||||
let isAlreadyDefined = true;
|
||||
|
||||
try {
|
||||
let test = this.world.getDynamicProperty(this.registerdStores[i].getName());
|
||||
if (test === undefined) {
|
||||
isAlreadyDefined = false;
|
||||
}
|
||||
} catch (e) {
|
||||
isAlreadyDefined = false;
|
||||
}
|
||||
if (isAlreadyDefined) {
|
||||
continue;
|
||||
}
|
||||
switch (this.registerdStores[i].getType()) {
|
||||
case StoreType.string:
|
||||
this.propertyManager.defineString(this.registerdStores[i].getName(), 25565);
|
||||
this.debugLog.push("registerd string" + this.registerdStores[i].getName());
|
||||
break;
|
||||
case StoreType.number:
|
||||
this.propertyManager.defineNumber(this.registerdStores[i].getName(), 0);
|
||||
this.debugLog.push("registerd number" + this.registerdStores[i].getName());
|
||||
break;
|
||||
case StoreType.boolean:
|
||||
this.propertyManager.defineBoolean(this.registerdStores[i].getName(), false);
|
||||
this.debugLog.push("registerd boolean" + this.registerdStores[i].getName());
|
||||
break;
|
||||
}
|
||||
}
|
||||
propertyRegistry.registerWorldDynamicProperties(this.propertyManager);
|
||||
this.initialised = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the value of a store.
|
||||
* @param store The name of the store.
|
||||
* @param value The value to set.
|
||||
*/
|
||||
set(store: string, value: string | number | boolean): void {
|
||||
if (this.registerdStores.find((s) => s.getName() === store)?.getType() != typeof value) {
|
||||
this.world.sendMessage(`Store ${store} is not of type ${typeof value}`);
|
||||
return;
|
||||
}
|
||||
system.run(() => {
|
||||
this.world.setDynamicProperty(store, value);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the value of a store.
|
||||
* @param store The name of the store.
|
||||
* @returns The value of the store, or undefined if the store is not defined.
|
||||
*/
|
||||
get(store: string): string | number | boolean | undefined {
|
||||
try {
|
||||
let data = this.world.getDynamicProperty(store);
|
||||
if (data === undefined) {
|
||||
this.world.sendMessage(`Store ${store} is not defined`);
|
||||
return undefined;
|
||||
}
|
||||
return data;
|
||||
} catch (e) {
|
||||
// this.world.sendMessage(`Store ${store} is not defined`);
|
||||
return undefined;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Increments the value of a store if it is a number.
|
||||
* @param store The name of the store.
|
||||
*/
|
||||
increment(store: string): void {
|
||||
let data = this.get(store);
|
||||
if (typeof data === "number") {
|
||||
this.set(store, data + 1);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles chat commands by executing the corresponding actions.
|
||||
* @param event The chat send after event.
|
||||
*/
|
||||
private secondWarning = false;
|
||||
chatCommands(event: ChatSendAfterEvent) {
|
||||
const command = event.message.split(" ")[0];
|
||||
const args = event.message.split(" ").slice(1);
|
||||
|
||||
if (command === "!get") {
|
||||
const store = event.message.split(" ")[1];
|
||||
const value = this.get(store);
|
||||
this.world.sendMessage(`Value of ${store} is ${value}`);
|
||||
}
|
||||
if (command === "!set") {
|
||||
const store = event.message.split(" ")[1];
|
||||
if (store === undefined) {
|
||||
this.world.sendMessage(`Please provide a store to set`);
|
||||
return;
|
||||
}
|
||||
const value = event.message.split(" ")[2];
|
||||
if (value === undefined) {
|
||||
this.world.sendMessage(`Please provide a value to set for ${store}`);
|
||||
return;
|
||||
}
|
||||
const type = event.message.split(" ")[3];
|
||||
|
||||
let actualType = this.getStores()
|
||||
.find((s) => s.getName() === store)
|
||||
?.getType();
|
||||
|
||||
if (actualType === undefined) {
|
||||
this.world.sendMessage(`Store ${store} is not defined`);
|
||||
return;
|
||||
}
|
||||
|
||||
switch (actualType) {
|
||||
case StoreType.string:
|
||||
this.set(store, String(value));
|
||||
break;
|
||||
case StoreType.number:
|
||||
if (isNaN(Number(value))) {
|
||||
this.world.sendMessage(`Can't parse ${value} as a number`);
|
||||
return;
|
||||
}
|
||||
this.set(store, Number(value));
|
||||
break;
|
||||
case StoreType.boolean:
|
||||
const ActualValue = value.toLowerCase();
|
||||
this.set(store, ActualValue === "true");
|
||||
break;
|
||||
}
|
||||
this.world.sendMessage(`Value of ${store} is ${value}`);
|
||||
}
|
||||
if (event.message.startsWith("!listStores")) {
|
||||
this.getStores().forEach((store) => {
|
||||
this.world.sendMessage(`${store.getName()} is ${store.getType()}`);
|
||||
});
|
||||
}
|
||||
if (command === "!deleteStores") {
|
||||
this.world.sendMessage("ARE YOU SURE YOU WANT TO DELETE ALL STORES? THIS COULD CAUSE ISSUES");
|
||||
this.world.sendMessage("If you are sure, type !deleteStoresConfirm");
|
||||
this.secondWarning = true;
|
||||
}
|
||||
if (this.secondWarning) {
|
||||
if (command === "!deleteStoresConfirm") {
|
||||
this.getStores().forEach((store) => {
|
||||
this.world.sendMessage(`Deleting ${store.getName()}`);
|
||||
this.world.removeDynamicProperty(store.getName());
|
||||
});
|
||||
this.secondWarning = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export { Mindkeeper, Store, StoreType };
|
||||
16
scripts/Commandeer/nextLevel.ts
Normal file
16
scripts/Commandeer/nextLevel.ts
Normal file
@@ -0,0 +1,16 @@
|
||||
class NextLevel {
|
||||
currentState = 0;
|
||||
states: Array<Function> = [];
|
||||
|
||||
constructor(states: Array<Function>) {
|
||||
this.states = states;
|
||||
}
|
||||
|
||||
update() {
|
||||
this.states[this.currentState]();
|
||||
}
|
||||
|
||||
next() {
|
||||
this.currentState++;
|
||||
}
|
||||
}
|
||||
99
scripts/Commandeer/pupeteer.ts
Normal file
99
scripts/Commandeer/pupeteer.ts
Normal file
@@ -0,0 +1,99 @@
|
||||
import { RawText, TicksPerSecond, TitleDisplayOptions, Vector3, World, system } from "@minecraft/server";
|
||||
import { delayedRun } from "./utils/waitUtil";
|
||||
|
||||
class Pupeteer {
|
||||
world: World;
|
||||
|
||||
constructor(world: World) {
|
||||
this.world = world;
|
||||
}
|
||||
|
||||
private getActualString(message: string): string | RawText {
|
||||
if (message.startsWith("%")) {
|
||||
const key = message.substring(1);
|
||||
return { rawtext: [{ translate: key }] };
|
||||
}
|
||||
return message;
|
||||
}
|
||||
|
||||
setActionBarTimed(message: string, duration: number): void {
|
||||
this.world.getPlayers().forEach((player) => {
|
||||
player.onScreenDisplay.setActionBar(this.getActualString(message));
|
||||
});
|
||||
delayedRun(() => {
|
||||
this.clearActionBar();
|
||||
}, duration * TicksPerSecond);
|
||||
}
|
||||
|
||||
setActionBar(message: string): void {
|
||||
this.world.getPlayers().forEach((player) => {
|
||||
player.onScreenDisplay.setActionBar(this.getActualString(message));
|
||||
});
|
||||
}
|
||||
|
||||
sendWorldMessage(message: string): void {
|
||||
this.world.sendMessage(this.getActualString(message));
|
||||
}
|
||||
|
||||
setTitleTimed(message: string, duration: number): void {
|
||||
this.world.getPlayers().forEach((player) => {
|
||||
let options: TitleDisplayOptions = {
|
||||
fadeInDuration: 20,
|
||||
fadeOutDuration: 20,
|
||||
stayDuration: duration * TicksPerSecond,
|
||||
};
|
||||
player.onScreenDisplay.setTitle(this.getActualString(message), options);
|
||||
});
|
||||
}
|
||||
|
||||
setTitle(message: string): void {
|
||||
this.world.getPlayers().forEach((player) => {
|
||||
player.onScreenDisplay.setTitle(message);
|
||||
});
|
||||
}
|
||||
|
||||
updateSubtitle(message: string): void {
|
||||
this.world.getPlayers().forEach((player) => {
|
||||
player.onScreenDisplay.updateSubtitle(this.getActualString(message));
|
||||
});
|
||||
}
|
||||
|
||||
clearTitle(): void {
|
||||
this.world.getPlayers().forEach((player) => {
|
||||
player.onScreenDisplay.setTitle("");
|
||||
});
|
||||
}
|
||||
|
||||
clearSubtitle(): void {
|
||||
this.world.getPlayers().forEach((player) => {
|
||||
player.onScreenDisplay.updateSubtitle("");
|
||||
});
|
||||
}
|
||||
|
||||
clearActionBar(): void {
|
||||
this.world.getPlayers().forEach((player) => {
|
||||
player.onScreenDisplay.setActionBar("");
|
||||
});
|
||||
}
|
||||
|
||||
testForLocation(location: Vector3, radius: number): boolean {
|
||||
let isPlayerInArea = false;
|
||||
this.world.getPlayers().forEach((player) => {
|
||||
let dx = location.x - player.location.x;
|
||||
let dy = location.y - player.location.y;
|
||||
let dz = location.z - player.location.z;
|
||||
|
||||
let distance = Math.sqrt(dx * dx + dy * dy + dz * dz);
|
||||
if (distance < radius) {
|
||||
isPlayerInArea = true;
|
||||
}
|
||||
});
|
||||
return isPlayerInArea;
|
||||
}
|
||||
|
||||
setNpcText(npcTag: string, sceneName: string) {
|
||||
this.world.getDimension("overworld").runCommand(`/dialogue change @e[tag=${npcTag}] ${sceneName} @a`);
|
||||
}
|
||||
}
|
||||
|
||||
export default Pupeteer;
|
||||
80
scripts/Commandeer/trail/trailEngine.ts
Normal file
80
scripts/Commandeer/trail/trailEngine.ts
Normal file
@@ -0,0 +1,80 @@
|
||||
import { MolangVariableMap, Vector3, world } from "@minecraft/server";
|
||||
import { Vector3Add } from "../utils/vectorUtils";
|
||||
import { TrailType } from "./trailTypes";
|
||||
|
||||
class TrailPoint {
|
||||
postion: Vector3;
|
||||
index: number;
|
||||
|
||||
constructor(position: Vector3, index: number) {
|
||||
this.postion = position;
|
||||
this.index = index;
|
||||
}
|
||||
|
||||
spawn() {
|
||||
let spawnPosition: Vector3 = Vector3Add(this.postion, { x: 0.5, y: 0.5, z: 0.5 });
|
||||
try {
|
||||
world
|
||||
.getDimension("overworld")
|
||||
.spawnParticle("minecraft:balloon_gas_particle", spawnPosition, new MolangVariableMap());
|
||||
} catch (e) {}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
class Trail {
|
||||
id: string;
|
||||
points: TrailPoint[] = [];
|
||||
currentPoint: number = 0;
|
||||
nextParticleTimer: number = 0;
|
||||
currentParticleCounter: number = 0;
|
||||
|
||||
calculatedLength: number = 0;
|
||||
constructor(id: string, nextParticleTimer: number = 5) {
|
||||
this.id = id;
|
||||
this.nextParticleTimer = nextParticleTimer;
|
||||
}
|
||||
|
||||
addPoint(point: TrailPoint) {
|
||||
this.points.push(point);
|
||||
|
||||
//this could be a one liner,
|
||||
let maxlength: number = 0;
|
||||
this.points.forEach((point) => {
|
||||
if (point.index > maxlength) {
|
||||
maxlength = point.index;
|
||||
}
|
||||
});
|
||||
this.calculatedLength = maxlength;
|
||||
}
|
||||
|
||||
fromTrail(trail: TrailType) {
|
||||
trail.points.forEach((point) => {
|
||||
this.addPoint(new TrailPoint(point.position, point.index));
|
||||
});
|
||||
}
|
||||
|
||||
spawnNext() {
|
||||
if (this.currentParticleCounter >= this.nextParticleTimer) {
|
||||
this.currentParticleCounter = 0;
|
||||
|
||||
this.points
|
||||
.filter((point) => {
|
||||
return point.index === this.currentPoint;
|
||||
})
|
||||
.forEach((point) => {
|
||||
point.spawn();
|
||||
});
|
||||
|
||||
this.currentPoint++;
|
||||
if (this.currentPoint >= this.calculatedLength) {
|
||||
this.currentPoint = 0;
|
||||
}
|
||||
} else {
|
||||
this.currentParticleCounter++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export { Trail, TrailPoint };
|
||||
13
scripts/Commandeer/trail/trailTypes.ts
Normal file
13
scripts/Commandeer/trail/trailTypes.ts
Normal file
@@ -0,0 +1,13 @@
|
||||
import { Vector3 } from "@minecraft/server";
|
||||
|
||||
type TrailPointType = {
|
||||
index: number;
|
||||
position: Vector3;
|
||||
};
|
||||
|
||||
type TrailType = {
|
||||
name: string;
|
||||
points: TrailPointType[];
|
||||
};
|
||||
|
||||
export { TrailPointType, TrailType };
|
||||
34
scripts/Commandeer/utils/agentUtils.ts
Normal file
34
scripts/Commandeer/utils/agentUtils.ts
Normal file
@@ -0,0 +1,34 @@
|
||||
import { MinecraftEntityTypes, Vector3, world } from "@minecraft/server";
|
||||
import { Vector3ToString, vector3 } from "./vectorUtils";
|
||||
function teleportAgent(position: Vector3) {
|
||||
world
|
||||
.getDimension("overworld")
|
||||
.runCommand(`/execute as @a run tp @e[type=agent] ${position.x} ${position.y} ${position.z}`);
|
||||
}
|
||||
|
||||
function isAgentAt(position: Vector3): boolean {
|
||||
let isAgentAt: boolean = false;
|
||||
world
|
||||
.getDimension("overworld")
|
||||
.getEntitiesAtBlockLocation(position)
|
||||
.forEach((entity) => {
|
||||
if (!entity.isValid()) {
|
||||
world.sendMessage("INVALID ENTITY");
|
||||
return;
|
||||
}
|
||||
if (entity.typeId == "minecraft:agent") {
|
||||
isAgentAt = true;
|
||||
}
|
||||
});
|
||||
return isAgentAt;
|
||||
}
|
||||
|
||||
function getAgentLocation(): Vector3 {
|
||||
let agentLocation: Vector3 = vector3(0, 0, 0);
|
||||
// let agent = world.getEntity(mindKeeper.get("agentid") as string);
|
||||
// agentLocation = agent!.location;
|
||||
|
||||
return agentLocation;
|
||||
}
|
||||
|
||||
export { teleportAgent, isAgentAt, getAgentLocation };
|
||||
62
scripts/Commandeer/utils/arrow.ts
Normal file
62
scripts/Commandeer/utils/arrow.ts
Normal file
@@ -0,0 +1,62 @@
|
||||
import { MolangVariableMap, Vector3, world } from "@minecraft/server";
|
||||
import { Vector3Add, vector3 } from "./vectorUtils";
|
||||
import { PARTICLES, spawnParticle } from "./particleUtils";
|
||||
|
||||
let arrowTemplate: Vector3[] = [
|
||||
vector3(0, 0, 0),
|
||||
|
||||
vector3(1, 1, 0),
|
||||
vector3(-1, 1, 0),
|
||||
|
||||
vector3(1.5, 2, 0),
|
||||
vector3(-1.5, 2, 0),
|
||||
|
||||
vector3(2, 3, 0),
|
||||
vector3(-2, 3, 0),
|
||||
|
||||
vector3(0, 1, 0),
|
||||
vector3(0, 2, 0),
|
||||
vector3(0, 3, 0),
|
||||
vector3(0, 4, 0),
|
||||
vector3(0, 5, 0),
|
||||
];
|
||||
|
||||
let offset: Vector3 = vector3(0, 0, 0);
|
||||
|
||||
let angleOffset = 0;
|
||||
let heightBobbing = 0;
|
||||
let tickCounter = 0;
|
||||
|
||||
function rotate(pos: Vector3, angle: number) {
|
||||
let x = pos.x;
|
||||
let z = pos.z;
|
||||
|
||||
let newX = x * Math.cos(angle) - z * Math.sin(angle);
|
||||
let newZ = x * Math.sin(angle) + z * Math.cos(angle);
|
||||
|
||||
return vector3(newX, pos.y, newZ);
|
||||
}
|
||||
|
||||
const particleData = new MolangVariableMap().setColorRGB("variable.color", {
|
||||
red: 1,
|
||||
green: 1,
|
||||
blue: 1,
|
||||
alpha: 1,
|
||||
});
|
||||
|
||||
function drawArrow(offsetPos: Vector3) {
|
||||
tickCounter++;
|
||||
if (tickCounter % 2 == 0) {
|
||||
angleOffset += 0.1;
|
||||
heightBobbing += 0.3;
|
||||
offset = vector3(46.5, 75, 220.5);
|
||||
arrowTemplate.forEach((pos) => {
|
||||
let rotatedPos = rotate(pos, angleOffset);
|
||||
let finalPos = Vector3Add(offsetPos, rotatedPos);
|
||||
finalPos.y += Math.sin(heightBobbing) / 2;
|
||||
spawnParticle(finalPos, PARTICLES.point, particleData);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
export { drawArrow };
|
||||
20
scripts/Commandeer/utils/levelUtils.ts
Normal file
20
scripts/Commandeer/utils/levelUtils.ts
Normal file
@@ -0,0 +1,20 @@
|
||||
import { BlockType, MinecraftBlockTypes, Vector3, world } from "@minecraft/server";
|
||||
|
||||
type Wall = {
|
||||
startPos: Vector3;
|
||||
endPos: Vector3;
|
||||
};
|
||||
|
||||
function clearWall(wall: Wall) {
|
||||
world.getDimension("overworld").fillBlocks(wall.startPos, wall.endPos, MinecraftBlockTypes.air);
|
||||
}
|
||||
|
||||
function fillWall(wall: Wall, block: BlockType) {
|
||||
world.getDimension("overworld").fillBlocks(wall.startPos, wall.endPos, block);
|
||||
}
|
||||
|
||||
function startLevel(commandBlockPos: Vector3) {
|
||||
world.getDimension("overworld").fillBlocks(commandBlockPos, commandBlockPos, MinecraftBlockTypes.redstoneBlock);
|
||||
}
|
||||
|
||||
export { Wall, clearWall, fillWall, startLevel };
|
||||
231
scripts/Commandeer/utils/particleUtils.ts
Normal file
231
scripts/Commandeer/utils/particleUtils.ts
Normal file
@@ -0,0 +1,231 @@
|
||||
import { MolangVariableMap, Vector3, world } from "@minecraft/server";
|
||||
import { Vector3Add, vector3 } from "./vectorUtils";
|
||||
|
||||
const bedrockParticles = [
|
||||
"minecraft:mobspell_emitter",
|
||||
"minecraft:villager_angry",
|
||||
"minecraft:bleach",
|
||||
"minecraft:breaking_item_icon",
|
||||
"minecraft:blockdust",
|
||||
"minecraft:bubble_column_up_particle",
|
||||
"minecraft:compfire_smoke_particle",
|
||||
"minecraft:campfire_tall_smoke_particle",
|
||||
"minecraft:cherry_leaves_particle",
|
||||
"minecraft:crop_growth_emitter",
|
||||
"minecraft:conduit_particle",
|
||||
"minecraft:critical_hit_emitter",
|
||||
"minecraft:bubble_column_down_particle",
|
||||
"minecraft:dolphin_move_particle",
|
||||
"minecraft:dragon_breath_trail",
|
||||
"minecraft:dragon_breath_lingering",
|
||||
"minecraft:lava_drip_particle",
|
||||
"minecraft:water_drip_particle",
|
||||
"minecraft:redstone_wire_dust_particle",
|
||||
"minecraft:sculk_sensor_redstone_particle",
|
||||
"minecraft:splash_spell_emitter",
|
||||
"minecraft:electric_spark__particle",
|
||||
"minecraft:enchanting_table_particle",
|
||||
"minecraft:endrod",
|
||||
"minecraft:balloon_gas_particle",
|
||||
"minecraft:evoker_spell",
|
||||
"minecraft:huge_explosion_emitter",
|
||||
"minecraft:falling_dust_red_sand_particle",
|
||||
"minecraft:falling_dust_sand_particle",
|
||||
"minecraft:falling_dust_gravel_particle",
|
||||
"minecraft:falling_dust_top_snow_particle",
|
||||
"minecraft:falling_dust_dragon_egg_particle",
|
||||
"minecraft:falling_dust_concrete_particle",
|
||||
"minecraft:falling_dust_scaffolding_particle",
|
||||
"minecraft:honey_drip_particle",
|
||||
"minecraft:nectar_drip_particle",
|
||||
"minecraft:obsidian_tear_particle",
|
||||
"minecraft:spore_blossom_shower_particle",
|
||||
"minecraft:water_splash_particle",
|
||||
"minecraft:sparkler_emitter",
|
||||
"minecraft:water_wake_particle",
|
||||
"minecraft:basic_flame_particle",
|
||||
"minecraft:flash",
|
||||
"minecraft:glow_particle",
|
||||
"minecraft:villager_happy",
|
||||
"minecraft:heart_particle",
|
||||
"minecraft:water_evaporation_actor_emitter",
|
||||
"minecraft:lava_particle",
|
||||
"minecraft:mobflame_emitter",
|
||||
"minecraft:mobflame_single",
|
||||
"minecraft:mycelium_dust_particle",
|
||||
"minecraft:note_particle",
|
||||
"minecraft:explode",
|
||||
"minecraft:mob_portal",
|
||||
"minecraft:rainsplash",
|
||||
"minecraft:basic_smoke_particle",
|
||||
"minecraft:snowflake_particle",
|
||||
"minecraft:soul_particle",
|
||||
"minecraft:blue_flame_particle",
|
||||
"minecraft:spore_blossom_ambient_particle",
|
||||
"minecraft:watersplash",
|
||||
"minecraft:terrain",
|
||||
"minecraft:totem_particle",
|
||||
"minecraft:tracking_emitter",
|
||||
"minecraft:vibration_signal",
|
||||
"minecraft:wax_particle",
|
||||
"minecraft:witchspell",
|
||||
];
|
||||
|
||||
const PARTICLES = {
|
||||
mobspell_emitter: "minecraft:mobspell_emitter",
|
||||
villager_angry: "minecraft:villager_angry",
|
||||
bleach: "minecraft:bleach",
|
||||
breaking_item_icon: "minecraft:breaking_item_icon",
|
||||
blockdust: "minecraft:blockdust",
|
||||
bubble_column_up_particle: "minecraft:bubble_column_up_particle",
|
||||
compfire_smoke_particle: "minecraft:compfire_smoke_particle",
|
||||
campfire_tall_smoke_particle: "minecraft:campfire_tall_smoke_particle",
|
||||
cherry_leaves_particle: "minecraft:cherry_leaves_particle",
|
||||
crop_growth_emitter: "minecraft:crop_growth_emitter",
|
||||
conduit_particle: "minecraft:conduit_particle",
|
||||
critical_hit_emitter: "minecraft:critical_hit_emitter",
|
||||
bubble_column_down_particle: "minecraft:bubble_column_down_particle",
|
||||
dolphin_move_particle: "minecraft:dolphin_move_particle",
|
||||
dragon_breath_trail: "minecraft:dragon_breath_trail",
|
||||
dragon_breath_lingering: "minecraft:dragon_breath_lingering",
|
||||
lava_drip_particle: "minecraft:lava_drip_particle",
|
||||
water_drip_particle: "minecraft:water_drip_particle",
|
||||
redstone_wire_dust_particle: "minecraft:redstone_wire_dust_particle",
|
||||
sculk_sensor_redstone_particle: "minecraft:sculk_sensor_redstone_particle",
|
||||
splash_spell_emitter: "minecraft:splash_spell_emitter",
|
||||
electric_spark__particle: "minecraft:electric_spark__particle",
|
||||
enchanting_table_particle: "minecraft:enchanting_table_particle",
|
||||
endrod: "minecraft:endrod",
|
||||
balloon_gas_particle: "minecraft:balloon_gas_particle",
|
||||
evoker_spell: "minecraft:evoker_spell",
|
||||
huge_explosion_emitter: "minecraft:huge_explosion_emitter",
|
||||
falling_dust_red_sand_particle: "minecraft:falling_dust_red_sand_particle",
|
||||
falling_dust_sand_particle: "minecraft:falling_dust_sand_particle",
|
||||
falling_dust_gravel_particle: "minecraft:falling_dust_gravel_particle",
|
||||
falling_dust_top_snow_particle: "minecraft:falling_dust_top_snow_particle",
|
||||
falling_dust_dragon_egg_particle: "minecraft:falling_dust_dragon_egg_particle",
|
||||
falling_dust_concrete_particle: "minecraft:falling_dust_concrete_particle",
|
||||
falling_dust_scaffolding_particle: "minecraft:falling_dust_scaffolding_particle",
|
||||
honey_drip_particle: "minecraft:honey_drip_particle",
|
||||
nectar_drip_particle: "minecraft:nectar_drip_particle",
|
||||
obsidian_tear_particle: "minecraft:obsidian_tear_particle",
|
||||
spore_blossom_shower_particle: "minecraft:spore_blossom_shower_particle",
|
||||
water_splash_particle: "minecraft:water_splash_particle",
|
||||
sparkler_emitter: "minecraft:sparkler_emitter",
|
||||
water_wake_particle: "minecraft:water_wake_particle",
|
||||
basic_flame_particle: "minecraft:basic_flame_particle",
|
||||
flash: "minecraft:flash",
|
||||
glow_particle: "minecraft:glow_particle",
|
||||
villager_happy: "minecraft:villager_happy",
|
||||
heart_particle: "minecraft:heart_particle",
|
||||
water_evaporation_actor_emitter: "minecraft:water_evaporation_actor_emitter",
|
||||
lava_particle: "minecraft:lava_particle",
|
||||
mobflame_emitter: "minecraft:mobflame_emitter",
|
||||
mobflame_single: "minecraft:mobflame_single",
|
||||
mycelium_dust_particle: "minecraft:mycelium_dust_particle",
|
||||
note_particle: "minecraft:note_particle",
|
||||
explode: "minecraft:explode",
|
||||
mob_portal: "minecraft:mob_portal",
|
||||
rainsplash: "minecraft:rainsplash",
|
||||
basic_smoke_particle: "minecraft:basic_smoke_particle",
|
||||
snowflake_particle: "minecraft:snowflake_particle",
|
||||
soul_particle: "minecraft:soul_particle",
|
||||
blue_flame_particle: "minecraft:blue_flame_particle",
|
||||
spore_blossom_ambient_particle: "minecraft:spore_blossom_ambient_particle",
|
||||
watersplash: "minecraft:watersplash",
|
||||
terrain: "minecraft:terrain",
|
||||
totem_particle: "minecraft:totem_particle",
|
||||
tracking_emitter: "minecraft:tracking_emitter",
|
||||
vibration_signal: "minecraft:vibration_signal",
|
||||
wax_particle: "minecraft:wax_particle",
|
||||
witchspell: "minecraft:witchspell",
|
||||
point: "codecosmos:point",
|
||||
};
|
||||
|
||||
class ParticleColumn {
|
||||
pos: Vector3;
|
||||
radius: number;
|
||||
pointsPerLayer: number;
|
||||
layerCount: number;
|
||||
particle: string;
|
||||
points: Vector3[] = [];
|
||||
speed: number;
|
||||
anglePerLayer: number[] = [];
|
||||
tickCounter: number = 0;
|
||||
|
||||
constructor(
|
||||
pos: Vector3,
|
||||
radius: number,
|
||||
pointsPerLayer: number,
|
||||
layerCount: number,
|
||||
speed: number,
|
||||
particle: string
|
||||
) {
|
||||
this.pos = pos;
|
||||
this.radius = radius;
|
||||
this.particle = particle;
|
||||
this.pointsPerLayer = pointsPerLayer;
|
||||
this.layerCount = layerCount;
|
||||
this.speed = speed;
|
||||
this.generatePoints();
|
||||
}
|
||||
|
||||
generatePoints() {
|
||||
for (let layer = 0; layer < this.layerCount; layer++) {
|
||||
let layerRadius = this.radius - layer;
|
||||
for (let point = 0; point < this.pointsPerLayer; point++) {
|
||||
let angle = (point / this.pointsPerLayer) * (Math.PI * 2);
|
||||
this.anglePerLayer.push(angle);
|
||||
let x = Math.cos(angle) * layerRadius;
|
||||
let z = Math.sin(angle) * layerRadius;
|
||||
let y = layer;
|
||||
this.points.push(Vector3Add(this.pos, vector3(x, y, z)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
update() {
|
||||
//update each point by increasing the angle by the speed
|
||||
let layerCount = 0;
|
||||
let pointCount = 0;
|
||||
this.tickCounter++;
|
||||
if (this.tickCounter % 2 == 0) {
|
||||
this.points.forEach((point, index) => {
|
||||
let layer = Math.floor(index / this.pointsPerLayer);
|
||||
let angle = this.anglePerLayer[index];
|
||||
angle += this.speed * (layer / 5);
|
||||
this.anglePerLayer[index] = angle;
|
||||
let layerRadius = this.radius - Math.floor(index / this.pointsPerLayer);
|
||||
let calcAngle = angle;
|
||||
let x = Math.cos(calcAngle) * this.radius;
|
||||
let z = Math.sin(calcAngle) * this.radius;
|
||||
let y = Math.floor(index / this.pointsPerLayer) + (this.tickCounter % 2);
|
||||
this.points[index] = Vector3Add(this.pos, vector3(x, y, z));
|
||||
});
|
||||
}
|
||||
}
|
||||
draw() {
|
||||
this.points.forEach((point) => {
|
||||
spawnParticle(point);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function spawnParticle(
|
||||
position: Vector3,
|
||||
particle: string = PARTICLES.balloon_gas_particle,
|
||||
map: MolangVariableMap = new MolangVariableMap()
|
||||
) {
|
||||
//check if the chunk is loaded
|
||||
const chunk = world.getDimension("overworld").getBlock(position);
|
||||
if (!chunk?.isValid) {
|
||||
return;
|
||||
}
|
||||
|
||||
const dimension = world.getDimension("overworld");
|
||||
if (dimension) {
|
||||
dimension.spawnParticle(particle, position, map);
|
||||
}
|
||||
}
|
||||
|
||||
export { PARTICLES, bedrockParticles, ParticleColumn, spawnParticle };
|
||||
66
scripts/Commandeer/utils/vectorUtils.ts
Normal file
66
scripts/Commandeer/utils/vectorUtils.ts
Normal file
@@ -0,0 +1,66 @@
|
||||
import { Vector3 } from "@minecraft/server";
|
||||
|
||||
function vector3(x: number, y: number, z: number): Vector3 {
|
||||
return { x: x, y: y, z: z };
|
||||
}
|
||||
|
||||
function Vector3ToString(vector: Vector3) {
|
||||
return vector.x + "," + vector.y + "," + vector.z;
|
||||
}
|
||||
|
||||
function Vector3ToFancyString(vector: Vector3) {
|
||||
return `{X: ${Math.floor(vector.x)}, Y: ${Math.floor(vector.y)}, Z: ${Math.floor(vector.z)}}`;
|
||||
}
|
||||
|
||||
function Vector3Add(vector1: Vector3, vector2: Vector3): Vector3 {
|
||||
return { x: vector1.x + vector2.x, y: vector1.y + vector2.y, z: vector1.z + vector2.z };
|
||||
}
|
||||
|
||||
function Vector3Subtract(vector1: Vector3, vector2: Vector3): Vector3 {
|
||||
return { x: vector1.x - vector2.x, y: vector1.y - vector2.y, z: vector1.z - vector2.z };
|
||||
}
|
||||
|
||||
function Vector3Multiply(vector1: Vector3, vector2: Vector3): Vector3 {
|
||||
return { x: vector1.x * vector2.x, y: vector1.y * vector2.y, z: vector1.z * vector2.z };
|
||||
}
|
||||
|
||||
function Vector3Divide(vector1: Vector3, vector2: Vector3): Vector3 {
|
||||
return { x: vector1.x / vector2.x, y: vector1.y / vector2.y, z: vector1.z / vector2.z };
|
||||
}
|
||||
|
||||
function Vector3Floor(vector: Vector3): Vector3 {
|
||||
return { x: Math.floor(vector.x), y: Math.floor(vector.y), z: Math.floor(vector.z) };
|
||||
}
|
||||
|
||||
function Vector3Ceil(vector: Vector3): Vector3 {
|
||||
return { x: Math.ceil(vector.x), y: Math.ceil(vector.y), z: Math.ceil(vector.z) };
|
||||
}
|
||||
|
||||
function Vector3Round(vector: Vector3): Vector3 {
|
||||
return { x: Math.round(vector.x), y: Math.round(vector.y), z: Math.round(vector.z) };
|
||||
}
|
||||
|
||||
function Vector3Abs(vector: Vector3): Vector3 {
|
||||
return { x: Math.abs(vector.x), y: Math.abs(vector.y), z: Math.abs(vector.z) };
|
||||
}
|
||||
|
||||
function vector3Distance(vector1: Vector3, vector2: Vector3): number {
|
||||
return Math.sqrt(
|
||||
Math.pow(vector2.x - vector1.x, 2) + Math.pow(vector2.y - vector1.y, 2) + Math.pow(vector2.z - vector1.z, 2)
|
||||
);
|
||||
}
|
||||
|
||||
export {
|
||||
Vector3ToString,
|
||||
Vector3ToFancyString,
|
||||
Vector3Add,
|
||||
Vector3Subtract,
|
||||
Vector3Multiply,
|
||||
Vector3Divide,
|
||||
Vector3Floor,
|
||||
Vector3Ceil,
|
||||
Vector3Round,
|
||||
Vector3Abs,
|
||||
vector3Distance,
|
||||
vector3,
|
||||
};
|
||||
16
scripts/Commandeer/utils/waitUtil.ts
Normal file
16
scripts/Commandeer/utils/waitUtil.ts
Normal file
@@ -0,0 +1,16 @@
|
||||
import { system } from "@minecraft/server";
|
||||
|
||||
function delayedRun(callback: Function, delay: number) {
|
||||
let timer = system.runTimeout(() => {
|
||||
callback();
|
||||
system.clearRun(timer);
|
||||
}, delay);
|
||||
}
|
||||
|
||||
function delay(t: number) {
|
||||
return new Promise((r: any) => {
|
||||
system.runTimeout(r, t);
|
||||
});
|
||||
}
|
||||
|
||||
export { delayedRun, delay };
|
||||
34
scripts/Commandeer/utils/worldEditUtils.ts
Normal file
34
scripts/Commandeer/utils/worldEditUtils.ts
Normal file
@@ -0,0 +1,34 @@
|
||||
import { Vector3, world } from "@minecraft/server";
|
||||
|
||||
function clone(startPos: Vector3, endPos: Vector3, destination: Vector3) {
|
||||
world
|
||||
.getDimension("overworld")
|
||||
.runCommand(
|
||||
`clone ${startPos.x} ${startPos.y} ${startPos.z} ${endPos.x} ${endPos.y} ${endPos.z} ${destination.x} ${destination.y} ${destination.z} replace normal`
|
||||
);
|
||||
}
|
||||
|
||||
enum LeverDirection {
|
||||
DownEastWest = "down_east_west",
|
||||
DownNorthSouth = "down_north_south",
|
||||
East = "east",
|
||||
North = "north",
|
||||
South = "south",
|
||||
UpEastWest = "up_east_west",
|
||||
UpNorthSouth = "up_north_south",
|
||||
West = "west",
|
||||
}
|
||||
|
||||
function setLever(pos: Vector3, direction: LeverDirection, isOpen: boolean) {
|
||||
world
|
||||
.getDimension("overworld")
|
||||
.runCommandAsync(
|
||||
`/setblock ${pos.x} ${pos.y} ${pos.z} lever["lever_direction":"${direction}","open_bit":${
|
||||
isOpen ? "true" : "false"
|
||||
}]`
|
||||
);
|
||||
|
||||
///setblock 53 70 216 lever["lever_direction"="down_east_west","open_bit"=false]
|
||||
}
|
||||
|
||||
export { clone, LeverDirection, setLever };
|
||||
140
scripts/levelConditions/level1.ts
Normal file
140
scripts/levelConditions/level1.ts
Normal file
@@ -0,0 +1,140 @@
|
||||
import { BlockType, MinecraftBlockTypes, Vector3 } from "@minecraft/server";
|
||||
import { LevelBlockCondition, LevelNoGoZone } from "../Commandeer/level/levelTypes";
|
||||
import { vector3 } from "../Commandeer/utils/vectorUtils";
|
||||
|
||||
let level1Conditions: LevelBlockCondition = {
|
||||
conditions: [
|
||||
{
|
||||
block: MinecraftBlockTypes.air,
|
||||
position: vector3(55, 70, 216),
|
||||
},
|
||||
{
|
||||
block: MinecraftBlockTypes.air,
|
||||
position: vector3(56, 70, 216),
|
||||
},
|
||||
{
|
||||
block: MinecraftBlockTypes.air,
|
||||
position: vector3(57, 70, 216),
|
||||
},
|
||||
{
|
||||
block: MinecraftBlockTypes.air,
|
||||
position: vector3(58, 70, 216),
|
||||
},
|
||||
{
|
||||
block: MinecraftBlockTypes.air,
|
||||
position: vector3(59, 70, 216),
|
||||
},
|
||||
{
|
||||
block: MinecraftBlockTypes.air,
|
||||
position: vector3(60, 70, 216),
|
||||
},
|
||||
{
|
||||
block: MinecraftBlockTypes.air,
|
||||
position: vector3(61, 70, 216),
|
||||
},
|
||||
{
|
||||
block: MinecraftBlockTypes.air,
|
||||
position: vector3(62, 70, 216),
|
||||
},
|
||||
{
|
||||
block: MinecraftBlockTypes.air,
|
||||
position: vector3(63, 70, 216),
|
||||
},
|
||||
{
|
||||
block: MinecraftBlockTypes.air,
|
||||
position: vector3(64, 70, 216),
|
||||
},
|
||||
{
|
||||
block: MinecraftBlockTypes.air,
|
||||
position: vector3(65, 70, 216),
|
||||
},
|
||||
{
|
||||
block: MinecraftBlockTypes.air,
|
||||
position: vector3(66, 70, 216),
|
||||
},
|
||||
{
|
||||
block: MinecraftBlockTypes.air,
|
||||
position: vector3(67, 70, 216),
|
||||
},
|
||||
{
|
||||
block: MinecraftBlockTypes.air,
|
||||
position: vector3(68, 70, 216),
|
||||
},
|
||||
{
|
||||
block: MinecraftBlockTypes.air,
|
||||
position: vector3(69, 70, 216),
|
||||
},
|
||||
{
|
||||
block: MinecraftBlockTypes.air,
|
||||
position: vector3(70, 70, 216),
|
||||
},
|
||||
{
|
||||
block: MinecraftBlockTypes.air,
|
||||
position: vector3(71, 70, 216),
|
||||
},
|
||||
{
|
||||
block: MinecraftBlockTypes.air,
|
||||
position: vector3(72, 70, 216),
|
||||
},
|
||||
{
|
||||
block: MinecraftBlockTypes.air,
|
||||
position: vector3(73, 70, 216),
|
||||
},
|
||||
{
|
||||
block: MinecraftBlockTypes.air,
|
||||
position: vector3(74, 70, 216),
|
||||
},
|
||||
{
|
||||
block: MinecraftBlockTypes.air,
|
||||
position: vector3(74, 70, 216),
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
let level1NoGoZones: LevelNoGoZone = {
|
||||
zones: [
|
||||
{ position: vector3(55, 70, 215) },
|
||||
{ position: vector3(56, 70, 215) },
|
||||
{ position: vector3(57, 70, 215) },
|
||||
{ position: vector3(58, 70, 215) },
|
||||
{ position: vector3(59, 70, 215) },
|
||||
{ position: vector3(60, 70, 215) },
|
||||
{ position: vector3(61, 70, 215) },
|
||||
{ position: vector3(62, 70, 215) },
|
||||
{ position: vector3(63, 70, 215) },
|
||||
{ position: vector3(64, 70, 215) },
|
||||
{ position: vector3(65, 70, 215) },
|
||||
{ position: vector3(66, 70, 215) },
|
||||
{ position: vector3(67, 70, 215) },
|
||||
{ position: vector3(68, 70, 215) },
|
||||
{ position: vector3(69, 70, 215) },
|
||||
{ position: vector3(70, 70, 215) },
|
||||
{ position: vector3(71, 70, 215) },
|
||||
{ position: vector3(72, 70, 215) },
|
||||
{ position: vector3(73, 70, 215) },
|
||||
{ position: vector3(74, 70, 215) },
|
||||
|
||||
{ position: vector3(55, 70, 217) },
|
||||
{ position: vector3(56, 70, 217) },
|
||||
{ position: vector3(57, 70, 217) },
|
||||
{ position: vector3(58, 70, 217) },
|
||||
{ position: vector3(59, 70, 217) },
|
||||
{ position: vector3(60, 70, 217) },
|
||||
{ position: vector3(61, 70, 217) },
|
||||
{ position: vector3(62, 70, 217) },
|
||||
{ position: vector3(63, 70, 217) },
|
||||
{ position: vector3(64, 70, 217) },
|
||||
{ position: vector3(65, 70, 217) },
|
||||
{ position: vector3(66, 70, 217) },
|
||||
{ position: vector3(67, 70, 217) },
|
||||
{ position: vector3(68, 70, 217) },
|
||||
{ position: vector3(69, 70, 217) },
|
||||
{ position: vector3(70, 70, 217) },
|
||||
{ position: vector3(71, 70, 217) },
|
||||
{ position: vector3(72, 70, 217) },
|
||||
{ position: vector3(73, 70, 217) },
|
||||
{ position: vector3(74, 70, 217) },
|
||||
],
|
||||
};
|
||||
|
||||
export { level1Conditions, level1NoGoZones };
|
||||
144
scripts/levelConditions/level2.ts
Normal file
144
scripts/levelConditions/level2.ts
Normal file
@@ -0,0 +1,144 @@
|
||||
import { BlockType, MinecraftBlockTypes, Vector3 } from "@minecraft/server";
|
||||
import { LevelBlockCondition, LevelNoGoZone } from "../Commandeer/level/levelTypes";
|
||||
import { vector3 } from "../Commandeer/utils/vectorUtils";
|
||||
|
||||
let level2Conditions: LevelBlockCondition = {
|
||||
conditions: [
|
||||
{
|
||||
block: MinecraftBlockTypes.air,
|
||||
position: vector3(45, 70, 220),
|
||||
},
|
||||
{
|
||||
block: MinecraftBlockTypes.air,
|
||||
position: vector3(44, 70, 220),
|
||||
},
|
||||
{
|
||||
block: MinecraftBlockTypes.air,
|
||||
position: vector3(43, 70, 220),
|
||||
},
|
||||
{
|
||||
block: MinecraftBlockTypes.air,
|
||||
position: vector3(42, 70, 220),
|
||||
},
|
||||
{
|
||||
block: MinecraftBlockTypes.air,
|
||||
position: vector3(41, 70, 220),
|
||||
},
|
||||
{
|
||||
block: MinecraftBlockTypes.air,
|
||||
position: vector3(40, 70, 220),
|
||||
},
|
||||
{
|
||||
block: MinecraftBlockTypes.air,
|
||||
position: vector3(39, 70, 220),
|
||||
},
|
||||
{
|
||||
block: MinecraftBlockTypes.air,
|
||||
position: vector3(38, 70, 220),
|
||||
},
|
||||
{
|
||||
block: MinecraftBlockTypes.air,
|
||||
position: vector3(37, 70, 220),
|
||||
},
|
||||
{
|
||||
block: MinecraftBlockTypes.air,
|
||||
position: vector3(36, 70, 220),
|
||||
},
|
||||
{
|
||||
block: MinecraftBlockTypes.air,
|
||||
position: vector3(35, 70, 220),
|
||||
},
|
||||
{
|
||||
block: MinecraftBlockTypes.air,
|
||||
position: vector3(34, 70, 220),
|
||||
},
|
||||
{
|
||||
block: MinecraftBlockTypes.air,
|
||||
position: vector3(33, 70, 220),
|
||||
},
|
||||
|
||||
{
|
||||
block: MinecraftBlockTypes.air,
|
||||
position: vector3(33, 70, 219),
|
||||
},
|
||||
{
|
||||
block: MinecraftBlockTypes.air,
|
||||
position: vector3(33, 70, 218),
|
||||
},
|
||||
{
|
||||
block: MinecraftBlockTypes.air,
|
||||
position: vector3(33, 70, 217),
|
||||
},
|
||||
{
|
||||
block: MinecraftBlockTypes.air,
|
||||
position: vector3(33, 70, 216),
|
||||
},
|
||||
{
|
||||
block: MinecraftBlockTypes.air,
|
||||
position: vector3(33, 70, 215),
|
||||
},
|
||||
{
|
||||
block: MinecraftBlockTypes.air,
|
||||
position: vector3(33, 70, 214),
|
||||
},
|
||||
{
|
||||
block: MinecraftBlockTypes.air,
|
||||
position: vector3(33, 70, 213),
|
||||
},
|
||||
{
|
||||
block: MinecraftBlockTypes.air,
|
||||
position: vector3(33, 70, 212),
|
||||
},
|
||||
|
||||
{
|
||||
block: MinecraftBlockTypes.air,
|
||||
position: vector3(34, 70, 212),
|
||||
},
|
||||
{
|
||||
block: MinecraftBlockTypes.air,
|
||||
position: vector3(35, 70, 212),
|
||||
},
|
||||
{
|
||||
block: MinecraftBlockTypes.air,
|
||||
position: vector3(36, 70, 212),
|
||||
},
|
||||
{
|
||||
block: MinecraftBlockTypes.air,
|
||||
position: vector3(37, 70, 212),
|
||||
},
|
||||
{
|
||||
block: MinecraftBlockTypes.air,
|
||||
position: vector3(38, 70, 212),
|
||||
},
|
||||
{
|
||||
block: MinecraftBlockTypes.air,
|
||||
position: vector3(39, 70, 212),
|
||||
},
|
||||
{
|
||||
block: MinecraftBlockTypes.air,
|
||||
position: vector3(40, 70, 212),
|
||||
},
|
||||
{
|
||||
block: MinecraftBlockTypes.air,
|
||||
position: vector3(41, 70, 212),
|
||||
},
|
||||
{
|
||||
block: MinecraftBlockTypes.air,
|
||||
position: vector3(42, 70, 212),
|
||||
},
|
||||
{
|
||||
block: MinecraftBlockTypes.air,
|
||||
position: vector3(43, 70, 212),
|
||||
},
|
||||
{
|
||||
block: MinecraftBlockTypes.air,
|
||||
position: vector3(44, 70, 212),
|
||||
},
|
||||
{
|
||||
block: MinecraftBlockTypes.air,
|
||||
position: vector3(45, 70, 212),
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
export { level2Conditions };
|
||||
139
scripts/levelConditions/level3.ts
Normal file
139
scripts/levelConditions/level3.ts
Normal file
@@ -0,0 +1,139 @@
|
||||
import { BlockType, MinecraftBlockTypes, Vector3 } from "@minecraft/server";
|
||||
import { LevelBlockCondition } from "../Commandeer/level/levelTypes";
|
||||
import { vector3 } from "../Commandeer/utils/vectorUtils";
|
||||
|
||||
let level3Conditions: LevelBlockCondition = {
|
||||
conditions: [
|
||||
{
|
||||
block: MinecraftBlockTypes.air,
|
||||
position: vector3(57, 70, 235),
|
||||
},
|
||||
{
|
||||
block: MinecraftBlockTypes.air,
|
||||
position: vector3(58, 70, 235),
|
||||
},
|
||||
{
|
||||
block: MinecraftBlockTypes.air,
|
||||
position: vector3(59, 70, 235),
|
||||
},
|
||||
{
|
||||
block: MinecraftBlockTypes.air,
|
||||
position: vector3(60, 70, 235),
|
||||
},
|
||||
{
|
||||
block: MinecraftBlockTypes.air,
|
||||
position: vector3(60, 70, 234),
|
||||
},
|
||||
{
|
||||
block: MinecraftBlockTypes.air,
|
||||
position: vector3(60, 70, 233),
|
||||
},
|
||||
{
|
||||
block: MinecraftBlockTypes.air,
|
||||
position: vector3(60, 70, 232),
|
||||
},
|
||||
{
|
||||
block: MinecraftBlockTypes.air,
|
||||
position: vector3(60, 70, 231),
|
||||
},
|
||||
|
||||
{
|
||||
block: MinecraftBlockTypes.air,
|
||||
position: vector3(61, 70, 231),
|
||||
},
|
||||
{
|
||||
block: MinecraftBlockTypes.air,
|
||||
position: vector3(62, 70, 231),
|
||||
},
|
||||
{
|
||||
block: MinecraftBlockTypes.air,
|
||||
position: vector3(63, 70, 231),
|
||||
},
|
||||
{
|
||||
block: MinecraftBlockTypes.air,
|
||||
position: vector3(64, 70, 231),
|
||||
},
|
||||
|
||||
{
|
||||
block: MinecraftBlockTypes.air,
|
||||
position: vector3(64, 70, 232),
|
||||
},
|
||||
{
|
||||
block: MinecraftBlockTypes.air,
|
||||
position: vector3(64, 70, 233),
|
||||
},
|
||||
{
|
||||
block: MinecraftBlockTypes.air,
|
||||
position: vector3(64, 70, 234),
|
||||
},
|
||||
{
|
||||
block: MinecraftBlockTypes.air,
|
||||
position: vector3(64, 70, 235),
|
||||
},
|
||||
{
|
||||
block: MinecraftBlockTypes.air,
|
||||
position: vector3(64, 70, 236),
|
||||
},
|
||||
{
|
||||
block: MinecraftBlockTypes.air,
|
||||
position: vector3(64, 70, 237),
|
||||
},
|
||||
{
|
||||
block: MinecraftBlockTypes.air,
|
||||
position: vector3(64, 70, 238),
|
||||
},
|
||||
{
|
||||
block: MinecraftBlockTypes.air,
|
||||
position: vector3(64, 70, 239),
|
||||
},
|
||||
|
||||
{
|
||||
block: MinecraftBlockTypes.air,
|
||||
position: vector3(65, 70, 239),
|
||||
},
|
||||
{
|
||||
block: MinecraftBlockTypes.air,
|
||||
position: vector3(66, 70, 239),
|
||||
},
|
||||
{
|
||||
block: MinecraftBlockTypes.air,
|
||||
position: vector3(67, 70, 239),
|
||||
},
|
||||
{
|
||||
block: MinecraftBlockTypes.air,
|
||||
position: vector3(68, 70, 239),
|
||||
},
|
||||
|
||||
{
|
||||
block: MinecraftBlockTypes.air,
|
||||
position: vector3(68, 70, 238),
|
||||
},
|
||||
{
|
||||
block: MinecraftBlockTypes.air,
|
||||
position: vector3(68, 70, 237),
|
||||
},
|
||||
{
|
||||
block: MinecraftBlockTypes.air,
|
||||
position: vector3(68, 70, 236),
|
||||
},
|
||||
{
|
||||
block: MinecraftBlockTypes.air,
|
||||
position: vector3(68, 70, 235),
|
||||
},
|
||||
|
||||
{
|
||||
block: MinecraftBlockTypes.air,
|
||||
position: vector3(69, 70, 235),
|
||||
},
|
||||
{
|
||||
block: MinecraftBlockTypes.air,
|
||||
position: vector3(70, 70, 235),
|
||||
},
|
||||
{
|
||||
block: MinecraftBlockTypes.air,
|
||||
position: vector3(71, 70, 235),
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
export { level3Conditions };
|
||||
26
scripts/levelConditions/levelIntro.ts
Normal file
26
scripts/levelConditions/levelIntro.ts
Normal file
@@ -0,0 +1,26 @@
|
||||
import { MinecraftBlockTypes } from "@minecraft/server";
|
||||
import { LevelBlockCondition, LevelLeverCondition } from "../Commandeer/level/levelTypes";
|
||||
import { vector3 } from "../Commandeer/utils/vectorUtils";
|
||||
|
||||
let levelIntroConditions: LevelBlockCondition = {
|
||||
conditions: [
|
||||
{
|
||||
block: MinecraftBlockTypes.emeraldBlock,
|
||||
position: vector3(2471, 12, 108),
|
||||
},
|
||||
{
|
||||
block: MinecraftBlockTypes.emeraldBlock,
|
||||
position: vector3(2469, 12, 108),
|
||||
},
|
||||
{
|
||||
block: MinecraftBlockTypes.lapisBlock,
|
||||
position: vector3(2468, 12, 108),
|
||||
},
|
||||
{
|
||||
block: MinecraftBlockTypes.lapisBlock,
|
||||
position: vector3(2464, 12, 108),
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
export { levelIntroConditions };
|
||||
223
scripts/main.ts
Normal file
223
scripts/main.ts
Normal file
@@ -0,0 +1,223 @@
|
||||
import {
|
||||
world,
|
||||
system,
|
||||
MinecraftBlockTypes,
|
||||
Vector3,
|
||||
MolangVariableMap,
|
||||
ChatSendAfterEvent,
|
||||
Player,
|
||||
Dimension,
|
||||
BlockType,
|
||||
Block,
|
||||
} from "@minecraft/server";
|
||||
import { Mindkeeper, Store, StoreType } from "./Commandeer/mindKeeper";
|
||||
import Pupeteer from "./Commandeer/pupeteer";
|
||||
import Level from "./Commandeer/level/level";
|
||||
import { leverOn } from "./Commandeer/level/levelTypes";
|
||||
import { levelIntroConditions } from "./levelConditions/levelIntro";
|
||||
import { Vector3ToFancyString, Vector3ToString, vector3 } from "./Commandeer/utils/vectorUtils";
|
||||
import { delay } from "./Commandeer/utils/waitUtil";
|
||||
import { PARTICLES, ParticleColumn, bedrockParticles, spawnParticle } from "./Commandeer/utils/particleUtils";
|
||||
import { drawArrow } from "./Commandeer/utils/arrow";
|
||||
import * as agentUtils from "./Commandeer/utils/agentUtils";
|
||||
import { level3Conditions } from "./levelConditions/level3";
|
||||
import { TrailMaker } from "./Commandeer/Makers/trailMaker";
|
||||
import * as CCTrigger from "./Commandeer/Trigger/CCTrigger";
|
||||
import { Command, Commands } from "./Commandeer/command/command";
|
||||
|
||||
const mindKeeper = new Mindkeeper(world);
|
||||
const pupeteer = new Pupeteer(world);
|
||||
const trailMaker: TrailMaker.Maker = new TrailMaker.Maker();
|
||||
const triggerManager = new CCTrigger.Manager(mindKeeper);
|
||||
const CURRENT_LEVEL = "currentLevel";
|
||||
const AGENT_ID = "agentid";
|
||||
const PREFIX = "!";
|
||||
export { pupeteer, mindKeeper, CURRENT_LEVEL };
|
||||
|
||||
const DEVELOPER_MODE = true;
|
||||
let tickCounter = 0;
|
||||
system.runInterval(() => {
|
||||
tickCounter++;
|
||||
if (mindKeeper.initialised) {
|
||||
trailMaker.Update();
|
||||
updateIntro();
|
||||
//run every 4 ticks
|
||||
if (tickCounter % 2 == 0) {
|
||||
triggerManager.Update();
|
||||
}
|
||||
const currentLevel = mindKeeper.get(CURRENT_LEVEL);
|
||||
switch (currentLevel) {
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
const buttonPositions: Vector3[] = [
|
||||
vector3(2471, 11, 106),
|
||||
vector3(2469, 11, 106),
|
||||
vector3(2468, 11, 106),
|
||||
vector3(2464, 11, 106),
|
||||
];
|
||||
|
||||
const blockPositions: Vector3[] = [
|
||||
vector3(2471, 12, 108),
|
||||
vector3(2469, 12, 108),
|
||||
vector3(2468, 12, 108),
|
||||
vector3(2464, 12, 108),
|
||||
];
|
||||
|
||||
let currentBlockSequence: BlockType[] = [];
|
||||
let currentBlockSeuqenceIndex: number[] = [];
|
||||
|
||||
triggerManager.RegisterFunctionTrigger("lightPath", (event) => {
|
||||
lightUpPath();
|
||||
});
|
||||
|
||||
//fill 2467 9 87 2468 9 105 redstone_block
|
||||
async function lightUpPath() {
|
||||
let overworld: Dimension = world.getDimension("overworld");
|
||||
let pos1 = vector3(2467, 9, 87);
|
||||
let pos2 = vector3(2468, 9, 105);
|
||||
|
||||
for (let z = pos2.z; z >= pos1.z; z--) {
|
||||
overworld.fillBlocks(vector3(pos1.x, pos1.y, z), vector3(pos1.x + 1, pos1.y, z), MinecraftBlockTypes.redstoneBlock);
|
||||
await delay(4);
|
||||
}
|
||||
// let pos2 = vector3(2468, 9, 105);
|
||||
}
|
||||
|
||||
const blockCycle: BlockType[] = [
|
||||
MinecraftBlockTypes.redstoneBlock,
|
||||
MinecraftBlockTypes.goldBlock,
|
||||
MinecraftBlockTypes.diamondBlock,
|
||||
MinecraftBlockTypes.emeraldBlock,
|
||||
MinecraftBlockTypes.lapisBlock,
|
||||
];
|
||||
|
||||
let buttonPressed: boolean[] = buttonPositions.map(() => false);
|
||||
|
||||
function startIntro() {
|
||||
//Determine the current squence
|
||||
|
||||
blockPositions.forEach((pos) => {
|
||||
let block = world.getDimension("overworld").getBlock(pos);
|
||||
let index = blockPositions.indexOf(pos);
|
||||
let blockType = block!.type;
|
||||
currentBlockSequence[index] = blockType;
|
||||
});
|
||||
}
|
||||
|
||||
function updateIntro() {
|
||||
//Check each button if it's pressed
|
||||
|
||||
buttonPositions.forEach((pos) => {
|
||||
let block = world.getDimension("overworld").getBlock(pos);
|
||||
let index = buttonPositions.indexOf(pos);
|
||||
let prevState = buttonPressed[index];
|
||||
let currentState = block!.getRedstonePower()! > 0;
|
||||
|
||||
if (currentState && !prevState) {
|
||||
buttonPressed[index] = true;
|
||||
//NextBlock
|
||||
let nextBlock = currentBlockSequence[index];
|
||||
let nextIndex = blockCycle.indexOf(nextBlock);
|
||||
nextIndex = (nextIndex + 1) % blockCycle.length;
|
||||
currentBlockSequence[index] = blockCycle[nextIndex];
|
||||
//Update the block
|
||||
let blockPos = blockPositions[index];
|
||||
world.getDimension("overworld").getBlock(blockPos)!.setType(blockCycle[nextIndex]);
|
||||
}
|
||||
|
||||
if (!currentState && prevState) {
|
||||
buttonPressed[index] = false;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
world.afterEvents.worldInitialize.subscribe(({ propertyRegistry }) => {
|
||||
mindKeeper.registerStore(CURRENT_LEVEL, StoreType.number);
|
||||
mindKeeper.registerStore(AGENT_ID, StoreType.string);
|
||||
// mindKeeper.set("ShowTriggers", true);
|
||||
triggerManager.RegisterStores();
|
||||
mindKeeper.registerToWorld(propertyRegistry);
|
||||
|
||||
triggerManager.Load();
|
||||
});
|
||||
|
||||
world.beforeEvents.itemUseOn.subscribe((event) => {
|
||||
trailMaker.OnItemUse(event);
|
||||
triggerManager.OnItemUse(event);
|
||||
});
|
||||
|
||||
function randomExplosions() {
|
||||
let pos1 = vector3(2465, 10, 82);
|
||||
let pos2 = vector3(2471, 18, 90);
|
||||
|
||||
for (let i = 0; i < 5; i++) {
|
||||
let pos = vector3(
|
||||
pos1.x + Math.random() * (pos2.x - pos1.x),
|
||||
pos1.y + Math.random() * (pos2.y - pos1.y),
|
||||
pos1.z + Math.random() * (pos2.z - pos1.z)
|
||||
);
|
||||
//create a particle
|
||||
spawnParticle(pos, "minecraft:huge_explosion_emitter", new MolangVariableMap());
|
||||
}
|
||||
}
|
||||
|
||||
let originalDoorPos = vector3(2465, 10, 82);
|
||||
let closedDoorPos = vector3(2465, 10, 82);
|
||||
let openDoorPos = vector3(2465, 10, 82);
|
||||
|
||||
let doorSize = vector3(7, 7, 7);
|
||||
///clone 2463 -10 81 2470 -3 87 2463 10 81
|
||||
///clone 2463 -30 81 2470 -23 87 2463 10 81
|
||||
|
||||
function blowUpDoor() {
|
||||
world.getDimension("overworld").runCommand("/clone 2463 -10 81 2470 -3 87 2463 10 81");
|
||||
}
|
||||
function restoreDoor() {
|
||||
world.getDimension("overworld").runCommand("/clone 2463 -30 81 2470 -23 87 2463 10 81");
|
||||
}
|
||||
|
||||
world.afterEvents.chatSend.subscribe((event: ChatSendAfterEvent) => {
|
||||
const command = event.message.split(" ")[0];
|
||||
|
||||
trailMaker.OnChat(event);
|
||||
mindKeeper.chatCommands(event);
|
||||
triggerManager.OnChat(event);
|
||||
|
||||
if (command === "!reset") {
|
||||
world.sendMessage("Resetting");
|
||||
}
|
||||
});
|
||||
|
||||
Commands.register(PREFIX, "info", (arg) => {
|
||||
world.sendMessage("-----------------");
|
||||
world.sendMessage("Current level: " + mindKeeper.get(CURRENT_LEVEL));
|
||||
world.sendMessage("Agent ID: " + mindKeeper.get(AGENT_ID));
|
||||
world.sendMessage("Engine Version: 1.0.2");
|
||||
world.sendMessage("Engine is running");
|
||||
world.sendMessage("Active players: " + world.getPlayers().length);
|
||||
world.sendMessage("Current dimension: " + arg.player.dimension.id);
|
||||
world.sendMessage("Current position: " + Vector3ToFancyString(arg.player.location));
|
||||
world.sendMessage("-----------------");
|
||||
});
|
||||
|
||||
Commands.register(PREFIX, "kboom", (arg) => {
|
||||
(async () => {
|
||||
for (let i = 0; i < 10; i++) {
|
||||
randomExplosions();
|
||||
await delay(1);
|
||||
}
|
||||
blowUpDoor();
|
||||
})();
|
||||
});
|
||||
|
||||
Commands.register(PREFIX, "restore", restoreDoor);
|
||||
|
||||
system.afterEvents.scriptEventReceive.subscribe((event) => {
|
||||
if (event.id == "cc:getId") {
|
||||
let id = event.message;
|
||||
world.sendMessage("Script got the id " + id);
|
||||
mindKeeper.set(AGENT_ID, id);
|
||||
}
|
||||
});
|
||||
66
scripts/trails/startTrail.ts
Normal file
66
scripts/trails/startTrail.ts
Normal file
@@ -0,0 +1,66 @@
|
||||
import { Vector3 } from "@minecraft/server";
|
||||
import { TrailType } from "../Commandeer/trail/trailTypes";
|
||||
import { vector3 } from "../Commandeer/utils/vectorUtils";
|
||||
|
||||
let startTrail: TrailType = {
|
||||
name: "startTrail",
|
||||
points: [
|
||||
{ index: 0, position: vector3(50, 70, 266) },
|
||||
{ index: 1, position: vector3(50, 70, 265) },
|
||||
{ index: 2, position: vector3(50, 70, 264) },
|
||||
{ index: 3, position: vector3(50, 70, 263) },
|
||||
{ index: 4, position: vector3(50, 70, 262) },
|
||||
{ index: 5, position: vector3(50, 70, 261) },
|
||||
{ index: 6, position: vector3(50, 70, 260) },
|
||||
{ index: 7, position: vector3(50, 70, 259) },
|
||||
{ index: 8, position: vector3(50, 70, 258) },
|
||||
{ index: 9, position: vector3(50, 70, 257) },
|
||||
{ index: 10, position: vector3(50, 70, 256) },
|
||||
{ index: 11, position: vector3(50, 70, 255) },
|
||||
{ index: 12, position: vector3(50, 70, 254) },
|
||||
{ index: 13, position: vector3(50, 70, 253) },
|
||||
{ index: 14, position: vector3(50, 70, 252) },
|
||||
{ index: 15, position: vector3(50, 70, 251) },
|
||||
{ index: 16, position: vector3(50, 70, 250) },
|
||||
{ index: 17, position: vector3(50, 70, 249) },
|
||||
{ index: 18, position: vector3(50, 70, 248) },
|
||||
{ index: 19, position: vector3(50, 70, 247) },
|
||||
{ index: 20, position: vector3(50, 70, 246) },
|
||||
{ index: 21, position: vector3(50, 70, 245) },
|
||||
{ index: 22, position: vector3(50, 70, 244) },
|
||||
{ index: 23, position: vector3(50, 70, 243) },
|
||||
{ index: 24, position: vector3(50, 70, 242) },
|
||||
{ index: 25, position: vector3(50, 70, 241) },
|
||||
{ index: 26, position: vector3(50, 70, 240) },
|
||||
{ index: 27, position: vector3(50, 70, 239) },
|
||||
{ index: 1, position: vector3(50, 70, 238) },
|
||||
{ index: 2, position: vector3(50, 70, 237) },
|
||||
{ index: 3, position: vector3(50, 70, 236) },
|
||||
{ index: 4, position: vector3(50, 70, 235) },
|
||||
{ index: 5, position: vector3(50, 70, 234) },
|
||||
{ index: 6, position: vector3(50, 70, 233) },
|
||||
{ index: 7, position: vector3(50, 70, 232) },
|
||||
{ index: 8, position: vector3(50, 70, 231) },
|
||||
{ index: 9, position: vector3(50, 70, 230) },
|
||||
{ index: 10, position: vector3(50, 70, 229) },
|
||||
{ index: 11, position: vector3(50, 70, 228) },
|
||||
{ index: 12, position: vector3(50, 70, 227) },
|
||||
{ index: 13, position: vector3(50, 70, 226) },
|
||||
{ index: 14, position: vector3(50, 70, 225) },
|
||||
{ index: 15, position: vector3(50, 70, 224) },
|
||||
{ index: 16, position: vector3(50, 70, 223) },
|
||||
{ index: 17, position: vector3(50, 70, 222) },
|
||||
{ index: 18, position: vector3(50, 70, 221) },
|
||||
{ index: 19, position: vector3(50, 70, 220) },
|
||||
{ index: 20, position: vector3(50, 70, 219) },
|
||||
{ index: 21, position: vector3(50, 70, 218) },
|
||||
{ index: 22, position: vector3(50, 70, 217) },
|
||||
{ index: 23, position: vector3(50, 70, 216) },
|
||||
{ index: 24, position: vector3(51, 70, 216) },
|
||||
{ index: 25, position: vector3(52, 70, 216) },
|
||||
{ index: 26, position: vector3(53, 70, 216) },
|
||||
{ index: 27, position: vector3(54, 70, 216) },
|
||||
],
|
||||
};
|
||||
|
||||
export { startTrail };
|
||||
45
scripts/triggers.ts
Normal file
45
scripts/triggers.ts
Normal file
@@ -0,0 +1,45 @@
|
||||
import { Dimension, MinecraftBlockTypes, world } from "@minecraft/server";
|
||||
import { CCTrigger } from "./Commandeer/Trigger/CCTrigger";
|
||||
import { mindKeeper } from "./main";
|
||||
import { vector3 } from "./Commandeer/utils/vectorUtils";
|
||||
import { delay } from "./Commandeer/utils/waitUtil";
|
||||
const triggerManager = new CCTrigger.Manager(mindKeeper);
|
||||
|
||||
triggerManager.RegisterFunctionTrigger("test", (event) => {
|
||||
world.sendMessage("Wow, this is a trigger :O");
|
||||
world.sendMessage("This was caused by " + event.player.name);
|
||||
});
|
||||
|
||||
triggerManager.RegisterFunctionTrigger("lightPath", (event) => {
|
||||
lightUpPath();
|
||||
});
|
||||
|
||||
triggerManager.RegisterFunctionTrigger("resetPath", (event) => {
|
||||
resetLightPath();
|
||||
});
|
||||
|
||||
//fill 2467 9 87 2468 9 105 redstone_block
|
||||
async function lightUpPath() {
|
||||
let overworld: Dimension = world.getDimension("overworld");
|
||||
let pos1 = vector3(2467, 9, 87);
|
||||
let pos2 = vector3(2468, 9, 105);
|
||||
|
||||
for (let z = pos2.z; z >= pos1.z; z--) {
|
||||
overworld.fillBlocks(vector3(pos1.x, pos1.y, z), vector3(pos1.x + 1, pos1.y, z), MinecraftBlockTypes.redstoneBlock);
|
||||
await delay(4);
|
||||
}
|
||||
// let pos2 = vector3(2468, 9, 105);
|
||||
}
|
||||
|
||||
async function resetLightPath() {
|
||||
world.getDimension("overworld").runCommand("/fill 2467 9 87 2468 9 105 air");
|
||||
}
|
||||
|
||||
triggerManager.RegisterFunctionTrigger("test2", (event) => {
|
||||
world.sendMessage("Wow, this is another trigger :O");
|
||||
});
|
||||
|
||||
triggerManager.RegisterFunctionTrigger("die", (event) => {
|
||||
world.sendMessage("You died");
|
||||
event.player.applyDamage(1000);
|
||||
});
|
||||
32
tsconfig.json
Normal file
32
tsconfig.json
Normal file
@@ -0,0 +1,32 @@
|
||||
{
|
||||
"compilerOptions":{
|
||||
"target":"es6",
|
||||
"moduleResolution":"node",
|
||||
"module":"es2020",
|
||||
"declaration":false,
|
||||
"noLib":false,
|
||||
"emitDecoratorMetadata":true,
|
||||
"experimentalDecorators":true,
|
||||
"sourceMap":true,
|
||||
"pretty":true,
|
||||
"forceConsistentCasingInFileNames": true,
|
||||
"strict": true,
|
||||
"allowUnreachableCode":true,
|
||||
"allowUnusedLabels":true,
|
||||
"noImplicitAny":true,
|
||||
"noImplicitReturns":false,
|
||||
"noImplicitUseStrict":false,
|
||||
"outDir":"build/",
|
||||
"rootDir": ".",
|
||||
"baseUrl":"behavior_packs/",
|
||||
"listFiles":false,
|
||||
"noEmitHelpers":true
|
||||
},
|
||||
"include":[
|
||||
"scripts/**/*"
|
||||
],
|
||||
"exclude":[
|
||||
"node_modules"
|
||||
],
|
||||
"compileOnSave":false
|
||||
}
|
||||
Reference in New Issue
Block a user