├── assets
├── diagram.png
├── siemcraft_logo.png
├── siemcraft_pig.png
├── siemcraft_command.png
├── siemcraft_settings.png
├── siemcraft_settings2.png
├── siemcraft_settings3.png
└── diamond_talk_sharable.pdf
├── .gitignore
├── siemcraft_addon_behavior
├── pack_icon.png
├── package.json
├── .vscode
│ └── launch.json
├── manifest.json
├── package-lock.json
├── spawn_rules
│ └── bear.json
├── scripts
│ └── server
│ │ └── server_scriptapi.js
└── entities
│ ├── chicken.json
│ ├── cow.json
│ ├── bear.json
│ ├── pig.json
│ ├── spider.json
│ └── panda.json
├── siemcraft_addon_gametest
├── pack_icon.png
├── manifest.json
└── scripts
│ └── script_gametest.js
├── siemcraft_addon_resource
├── pack_icon.png
├── textures
│ └── entity
│ │ └── bear.png
├── manifest.json
└── entity
│ └── bear.entity.json
├── run.ps1
├── rules
├── security.yml
├── where.yml
└── whoami.yml
├── example_agent_configs
├── sealighter_config.json
└── sysmon_config.xml
├── src
├── stringset.go
├── main.go
├── eventlogger.go
├── rules.go
└── minecraft.go
├── go.mod
├── .github
└── workflows
│ ├── main.yml
│ └── release.yml
├── test_websocket.py
├── README.md
└── go.sum
/assets/diagram.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pathtofile/siemcraft/HEAD/assets/diagram.png
--------------------------------------------------------------------------------
/assets/siemcraft_logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pathtofile/siemcraft/HEAD/assets/siemcraft_logo.png
--------------------------------------------------------------------------------
/assets/siemcraft_pig.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pathtofile/siemcraft/HEAD/assets/siemcraft_pig.png
--------------------------------------------------------------------------------
/assets/siemcraft_command.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pathtofile/siemcraft/HEAD/assets/siemcraft_command.png
--------------------------------------------------------------------------------
/assets/siemcraft_settings.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pathtofile/siemcraft/HEAD/assets/siemcraft_settings.png
--------------------------------------------------------------------------------
/assets/siemcraft_settings2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pathtofile/siemcraft/HEAD/assets/siemcraft_settings2.png
--------------------------------------------------------------------------------
/assets/siemcraft_settings3.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pathtofile/siemcraft/HEAD/assets/siemcraft_settings3.png
--------------------------------------------------------------------------------
/assets/diamond_talk_sharable.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pathtofile/siemcraft/HEAD/assets/diamond_talk_sharable.pdf
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | bin/*
2 | *.mcpack
3 | rulesbad
4 |
5 | # Used for debugging scripts
6 | siemcraft_addon_behavior/node_modules
7 |
--------------------------------------------------------------------------------
/siemcraft_addon_behavior/pack_icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pathtofile/siemcraft/HEAD/siemcraft_addon_behavior/pack_icon.png
--------------------------------------------------------------------------------
/siemcraft_addon_gametest/pack_icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pathtofile/siemcraft/HEAD/siemcraft_addon_gametest/pack_icon.png
--------------------------------------------------------------------------------
/siemcraft_addon_resource/pack_icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pathtofile/siemcraft/HEAD/siemcraft_addon_resource/pack_icon.png
--------------------------------------------------------------------------------
/siemcraft_addon_resource/textures/entity/bear.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pathtofile/siemcraft/HEAD/siemcraft_addon_resource/textures/entity/bear.png
--------------------------------------------------------------------------------
/run.ps1:
--------------------------------------------------------------------------------
1 | # Build
2 | $ErrorActionPreference = "Stop"
3 | . "$PSScriptRoot\build.ps1"
4 |
5 | # Run
6 | "$PSScriptRoot\bin\siemcraft.exe -rules $PSScriptRoot\rules"
7 |
--------------------------------------------------------------------------------
/siemcraft_addon_behavior/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "dependencies": {
3 | "@types/mojang-gametest": "^0.1.3",
4 | "@types/mojang-minecraft": "^0.1.3"
5 | }
6 | }
7 |
--------------------------------------------------------------------------------
/siemcraft_addon_behavior/.vscode/launch.json:
--------------------------------------------------------------------------------
1 | {
2 | "version": "0.2.0",
3 | "configurations": [
4 | {
5 | "type": "minecraft-js",
6 | "request": "attach",
7 | "name": "Wait for Minecraft Debug Connections",
8 | "mode": "listen",
9 | "localRoot": "${workspaceFolder}/",
10 | "port": 19144
11 | }
12 | ]
13 | }
--------------------------------------------------------------------------------
/rules/security.yml:
--------------------------------------------------------------------------------
1 | title: Security Logon
2 | id: bf10b06b-7dff-44d8-abd3-e07627253797
3 | status: experimental
4 | description: A user's local group membership was enumerated.
5 | author: pathtofile
6 | date: 2022/01/15
7 | references:
8 | - https://blog.tofile.dev
9 | logsource:
10 | product: windows
11 | service: security
12 | detection:
13 | selection:
14 | EventID:
15 | - 4798
16 | condition: selection
17 | falsepositives:
18 | - unknown
19 | level: low
20 |
--------------------------------------------------------------------------------
/example_agent_configs/sealighter_config.json:
--------------------------------------------------------------------------------
1 | {
2 | "session_properties": {
3 | "session_name": "Sealighter-Kernel-Process-Start",
4 | "output_format": "event_log"
5 | },
6 | "kernel_traces": [
7 | {
8 | "trace_name": "kernel_proc_start_trace",
9 | "provider_name": "process",
10 | "filters": {
11 | "any_of": {
12 | "opcode_is": 1
13 | }
14 | }
15 | }
16 | ]
17 | }
18 |
--------------------------------------------------------------------------------
/rules/where.yml:
--------------------------------------------------------------------------------
1 | title: Where Execution
2 | id: a9b9ff07-24d0-4f21-9af6-035aa26fee98
3 | status: experimental
4 | description: Where.exe runs
5 | references:
6 | - https://blog.tofile.dev
7 | tags:
8 | - attack.execution
9 | author: pathtofile
10 | date: 2022/01/15
11 | logsource:
12 | category: process_creation
13 | product: windows
14 | detection:
15 | selection:
16 | Image|endswith: '\where.exe'
17 | condition: selection
18 | falsepositives:
19 | - unknown
20 | level: low
21 |
--------------------------------------------------------------------------------
/rules/whoami.yml:
--------------------------------------------------------------------------------
1 | title: Whoami Execution
2 | id: 36de6a23-651e-485a-ba69-3966d66707af
3 | status: experimental
4 | description: Whoami.exe runs
5 | references:
6 | - https://blog.tofile.dev
7 | tags:
8 | - attack.execution
9 | author: pathtofile
10 | date: 2022/01/15
11 | logsource:
12 | category: process_creation
13 | product: windows
14 | detection:
15 | selection:
16 | Image|endswith: '\whoami.exe'
17 | condition: selection
18 | falsepositives:
19 | - unknown
20 | level: high
21 |
--------------------------------------------------------------------------------
/siemcraft_addon_resource/manifest.json:
--------------------------------------------------------------------------------
1 | {
2 | "format_version": 2,
3 | "header": {
4 | "description": "SIEMCraft Resource",
5 | "name": "SIEMCraft Resource",
6 | "uuid": "9b761fbc-67d0-4432-a2da-59e52dbafc2e",
7 | "version": [1, 0, 0],
8 | "min_engine_version": [ 1, 18, 0 ]
9 | },
10 | "modules": [
11 | {
12 | "description": "SIEMCraft Resource",
13 | "type": "resources",
14 | "uuid": "964aca52-81a3-4884-8238-c0cd7b3740cd",
15 | "version": [1, 0, 0]
16 | }
17 | ]
18 | }
19 |
--------------------------------------------------------------------------------
/example_agent_configs/sysmon_config.xml:
--------------------------------------------------------------------------------
1 |
2 | md5,sha256
3 |
4 |
5 |
6 |
7 |
8 |
9 | whoami.exe
10 | where.exe
11 |
12 |
13 |
14 |
15 |
--------------------------------------------------------------------------------
/src/stringset.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import (
4 | "fmt"
5 | "strings"
6 | )
7 |
8 | // Used to handle channels as an array in the commandline arguments
9 | type stringSet []string
10 |
11 | type Value interface {
12 | String() string
13 | Set(string) error
14 | }
15 |
16 | func (i *stringSet) String() string {
17 | return fmt.Sprintf("%s", *i)
18 | }
19 |
20 | func (i *stringSet) Set(values string) error {
21 | // Split by comman, but only add new values
22 | for _, value := range strings.Split(values, ",") {
23 | for _, channel := range *i {
24 | if value == channel {
25 | return nil
26 | }
27 | }
28 | *i = append(*i, []string{value}...)
29 | }
30 | return nil
31 | }
32 |
--------------------------------------------------------------------------------
/siemcraft_addon_behavior/manifest.json:
--------------------------------------------------------------------------------
1 | {
2 | "format_version": 2,
3 | "header": {
4 | "description": "SIEMCraft Behavior",
5 | "name": "SIEMCraft Behavior",
6 | "uuid": "3325c3d1-7424-45d1-af5c-bcfefff938b3",
7 | "version": [1, 0, 0],
8 | "min_engine_version": [ 1, 18, 0 ]
9 | },
10 | "modules": [
11 | {
12 | "description": "SIEMCraft Behavior",
13 | "type": "data",
14 | "uuid": "c2db45b6-b6cc-4809-a079-313c3e1a9471",
15 | "version": [1, 0, 0]
16 | }
17 | ],
18 | "dependencies": [
19 | {
20 | "uuid": "9b761fbc-67d0-4432-a2da-59e52dbafc2e",
21 | "version": [1, 0, 0]
22 | },
23 | {
24 | "uuid": "b26a4d4c-afdf-4690-88f8-931846312678",
25 | "version": [ 0, 1, 0 ]
26 | },
27 | {
28 | "uuid": "6f4b6893-1bb6-42fd-b458-7fa3d0c89616",
29 | "version": [ 0, 1, 0 ]
30 | }
31 | ]
32 | }
33 |
--------------------------------------------------------------------------------
/siemcraft_addon_gametest/manifest.json:
--------------------------------------------------------------------------------
1 | {
2 | "format_version": 2,
3 | "header": {
4 | "description": "SIEMCraft GameTest",
5 | "name": "SIEMCraft GameTest",
6 | "uuid": "408a9640-e490-4e9b-9b6e-88f63e5eb27a",
7 | "version": [1, 0, 0],
8 | "min_engine_version": [ 1, 18, 0 ]
9 | },
10 | "modules": [
11 | {
12 | "description": "SIEMCraft GameTest Script",
13 | "type": "script",
14 | "language": "javascript",
15 | "uuid": "ead57a90-41fc-4f3b-8e1a-ccc64c99da0c",
16 | "version": [1, 0, 0],
17 | "entry": "scripts/script_gametest.js"
18 | }
19 | ],
20 | "dependencies": [
21 | {
22 | "uuid": "9b761fbc-67d0-4432-a2da-59e52dbafc2e",
23 | "version": [1, 0, 0]
24 | },
25 | {
26 | "uuid": "b26a4d4c-afdf-4690-88f8-931846312678",
27 | "version": [ 0, 1, 0 ]
28 | },
29 | {
30 | "uuid": "6f4b6893-1bb6-42fd-b458-7fa3d0c89616",
31 | "version": [ 0, 1, 0 ]
32 | }
33 | ]
34 | }
35 |
--------------------------------------------------------------------------------
/go.mod:
--------------------------------------------------------------------------------
1 | module github.com/pathtofile/siemcraft
2 |
3 | go 1.17
4 |
5 | require (
6 | github.com/0xrawsec/golang-win32 v1.0.10
7 | github.com/bradleyjkemp/sigma-go v0.2.8
8 | github.com/pathtofile/mcwss v1.2.2
9 | golang.org/x/sync v0.0.0-20210220032951-036812b2e83c
10 | golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6
11 | )
12 |
13 | require (
14 | github.com/0xrawsec/golang-utils v1.1.8 // indirect
15 | github.com/PaesslerAG/gval v1.0.0 // indirect
16 | github.com/PaesslerAG/jsonpath v0.1.1 // indirect
17 | github.com/alecthomas/participle v0.7.1 // indirect
18 | github.com/google/uuid v1.1.0 // indirect
19 | github.com/gorilla/websocket v1.4.0 // indirect
20 | github.com/mattn/go-colorable v0.1.12 // indirect
21 | github.com/onsi/ginkgo v1.16.5 // indirect
22 | github.com/onsi/gomega v1.17.0 // indirect
23 | github.com/sergi/go-diff v1.0.0 // indirect
24 | github.com/stretchr/testify v1.7.0 // indirect
25 | github.com/yudai/gojsondiff v1.0.0 // indirect
26 | github.com/yudai/golcs v0.0.0-20170316035057-ecda9a501e82 // indirect
27 | github.com/yudai/pp v2.0.1+incompatible // indirect
28 | gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776 // indirect
29 | )
30 |
--------------------------------------------------------------------------------
/siemcraft_addon_resource/entity/bear.entity.json:
--------------------------------------------------------------------------------
1 | {
2 | "format_version": "1.8.0",
3 | "minecraft:client_entity": {
4 | "description": {
5 | "identifier": "siemcraft:bear",
6 | "materials": {
7 | "default": "polar_bear"
8 | },
9 | "textures": {
10 | "default": "textures/entity/bear"
11 | },
12 | "geometry": {
13 | "default": "geometry.polarbear"
14 | },
15 | "animations": {
16 | "walk": "animation.quadruped.walk",
17 | "move": "animation.polarbear.move",
18 | "look_at_target": "animation.common.look_at_target",
19 | "baby_transform": "animation.polarbear.baby_transform"
20 | },
21 | "scripts": {
22 | "scale": "1.2"
23 | },
24 | "animation_controllers": [
25 | {
26 | "move": "controller.animation.polarbear.move"
27 | },
28 | {
29 | "baby": "controller.animation.polarbear.baby"
30 | }
31 | ],
32 | "render_controllers": [
33 | "controller.render.polarbear"
34 | ],
35 | "spawn_egg": {
36 | "texture": "spawn_egg",
37 | "texture_index": 37
38 | }
39 | }
40 | }
41 | }
--------------------------------------------------------------------------------
/.github/workflows/main.yml:
--------------------------------------------------------------------------------
1 | name: CI
2 |
3 | on:
4 | push:
5 | branches: [ main ]
6 | pull_request:
7 | branches: [ main ]
8 | workflow_dispatch:
9 |
10 | jobs:
11 | build:
12 | runs-on: windows-latest
13 | steps:
14 | - name: Checkout code
15 | uses: actions/checkout@v2
16 | with:
17 | submodules: recursive
18 |
19 | - name: Install Go
20 | uses: actions/setup-go@v2
21 | with:
22 | go-version: '1.17.6'
23 |
24 | - name: Build binary
25 | run: go build -o .\bin\siemcraft.exe ./src
26 |
27 | - name: Build Behavior addon
28 | run: Compress-Archive -Path .\siemcraft_addon_behavior -DestinationPath .\bin\siemcraft_addon_behavior.mcpack -Force
29 |
30 | - name: Build Resource addon
31 | run: Compress-Archive -Path .\siemcraft_addon_resource -DestinationPath .\bin\siemcraft_addon_resource.mcpack -Force
32 |
33 | - name: Build GeteTest addon
34 | run: Compress-Archive -Path .\siemcraft_addon_gametest -DestinationPath .\bin\siemcraft_addon_gametest.mcpack -Force
35 |
36 | - name: Package addon
37 | run: Compress-Archive -Path .\bin\*.mcpack -DestinationPath .\bin\siemcraft.mcaddon -Force
38 |
--------------------------------------------------------------------------------
/siemcraft_addon_gametest/scripts/script_gametest.js:
--------------------------------------------------------------------------------
1 | import { world, BlockLocation, GameMode } from "mojang-minecraft";
2 | import * as GameTest from "mojang-gametest";
3 |
4 | const dim = world.getDimension("overworld");
5 |
6 | function sendMessage(message) {
7 | dim.runCommand(`tell @a "${message}"`);
8 | }
9 |
10 | world.events.dataDrivenEntityTriggerEvent.subscribe((eventData) => {
11 | var event_name = eventData.id;
12 | // Entity object, see: https://docs.microsoft.com/en-us/minecraft/creator/scriptapi/mojang-minecraft/entity
13 | var entity = eventData.entity;
14 |
15 | // Ignore other events
16 | // We can also filter out things when calling .subscribe(), but for now do it this way
17 | if (event_name != "special_death_event" && event_name != "special_death_event_diamond") {
18 | return;
19 | }
20 |
21 | // Get JSON event from tag
22 | var eventb64 = entity.getTags()[0];
23 | var prefix = "[SIEMCRAFT]";
24 | if (!eventb64.startsWith(prefix)) {
25 | return;
26 | }
27 | eventb64 = eventb64.slice(prefix.length);
28 |
29 | // Send message as a JSON string
30 | var weapon = "other_weapon";
31 | if (event_name == "special_death_event_diamond") {
32 | weapon = "diamond_sword";
33 | }
34 | var message = prefix + `{"eventb64": "${eventb64}", "item": "${weapon}", "projectile": "" }`;
35 | sendMessage(message);
36 | });
37 |
--------------------------------------------------------------------------------
/siemcraft_addon_behavior/package-lock.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "siemcraft_addon_behavior",
3 | "lockfileVersion": 2,
4 | "requires": true,
5 | "packages": {
6 | "": {
7 | "dependencies": {
8 | "@types/mojang-gametest": "^0.1.3",
9 | "@types/mojang-minecraft": "^0.1.3"
10 | }
11 | },
12 | "node_modules/@types/mojang-gametest": {
13 | "version": "0.1.3",
14 | "resolved": "https://registry.npmjs.org/@types/mojang-gametest/-/mojang-gametest-0.1.3.tgz",
15 | "integrity": "sha512-qQkdymiWX60g2Y4ObpUKqTCXMgWP3WIH8jr7knvmfgudZwGMs26lbZWQZBJzZtu09sPwcJZKGbuUx/sbeCLnpg==",
16 | "dependencies": {
17 | "@types/mojang-minecraft": "*"
18 | }
19 | },
20 | "node_modules/@types/mojang-minecraft": {
21 | "version": "0.1.3",
22 | "resolved": "https://registry.npmjs.org/@types/mojang-minecraft/-/mojang-minecraft-0.1.3.tgz",
23 | "integrity": "sha512-i6YWCGcAVAyyRr9mVaSvJlrnMQYXa23A4LnxI3vhpN9Osr0lx3gehu64nn1FiwpYf/JocMlattF+VePk0f3YVg=="
24 | }
25 | },
26 | "dependencies": {
27 | "@types/mojang-gametest": {
28 | "version": "0.1.3",
29 | "resolved": "https://registry.npmjs.org/@types/mojang-gametest/-/mojang-gametest-0.1.3.tgz",
30 | "integrity": "sha512-qQkdymiWX60g2Y4ObpUKqTCXMgWP3WIH8jr7knvmfgudZwGMs26lbZWQZBJzZtu09sPwcJZKGbuUx/sbeCLnpg==",
31 | "requires": {
32 | "@types/mojang-minecraft": "*"
33 | }
34 | },
35 | "@types/mojang-minecraft": {
36 | "version": "0.1.3",
37 | "resolved": "https://registry.npmjs.org/@types/mojang-minecraft/-/mojang-minecraft-0.1.3.tgz",
38 | "integrity": "sha512-i6YWCGcAVAyyRr9mVaSvJlrnMQYXa23A4LnxI3vhpN9Osr0lx3gehu64nn1FiwpYf/JocMlattF+VePk0f3YVg=="
39 | }
40 | }
41 | }
42 |
--------------------------------------------------------------------------------
/siemcraft_addon_behavior/spawn_rules/bear.json:
--------------------------------------------------------------------------------
1 | {
2 | "format_version": "1.8.0",
3 | "minecraft:spawn_rules": {
4 | "description": {
5 | "identifier": "siemcraft:bear",
6 | "population_control": "animal"
7 | },
8 | "conditions": [
9 | {
10 | "minecraft:spawns_on_surface": {},
11 | "minecraft:spawns_on_block_filter": [
12 | "minecraft:grass",
13 | "minecraft:podzol",
14 | "minecraft:dirt"
15 | ],
16 | "minecraft:brightness_filter": {
17 | "min": 7,
18 | "max": 15,
19 | "adjust_for_weather": false
20 | },
21 | "minecraft:weight": {
22 | "default": 1
23 | },
24 | "minecraft:herd": {
25 | "min_size": 1,
26 | "max_size": 2,
27 | "event":"minecraft:entity_born",
28 | "event_skip_count": 1
29 | },
30 |
31 | "minecraft:biome_filter": [
32 | {"test": "has_biome_tag", "operator":"==", "value": "taiga"}
33 | ]
34 | },
35 | {
36 | "minecraft:spawns_on_surface": {},
37 | "minecraft:spawns_on_block_filter": "minecraft:grass",
38 | "minecraft:brightness_filter": {
39 | "min": 7,
40 | "max": 15,
41 | "adjust_for_weather": false
42 | },
43 | "minecraft:weight": {
44 | "default": 5
45 | },
46 | "minecraft:herd": {
47 | "min_size": 1,
48 | "max_size": 2,
49 | "event":"minecraft:entity_born",
50 | "event_skip_count": 1
51 | },
52 |
53 | "minecraft:biome_filter": [
54 | {"test": "has_biome_tag", "operator":"==", "value": "taiga"}
55 | ]
56 | }
57 | ]
58 | }
59 | }
--------------------------------------------------------------------------------
/test_websocket.py:
--------------------------------------------------------------------------------
1 | import argparse
2 | from ast import parse
3 | import asyncio
4 | import websockets
5 | import json
6 | from uuid import uuid4
7 |
8 | EVENT_TYPE = "PlayerMessage"
9 |
10 | async def mineproxy(websocket, _):
11 | print('Connected')
12 |
13 | # Tell Minecraft to send all chat messages. Required once after Minecraft starts
14 | await websocket.send(
15 | json.dumps({
16 | "header": {
17 | "version": 1, # We're using the version 1 message protocol
18 | "requestId": str(uuid4()), # A unique ID for the request
19 | "messageType": "commandRequest", # This is a request ...
20 | "messagePurpose": "subscribe" # ... to subscribe to ...
21 | },
22 | "body": {
23 | "eventName": EVENT_TYPE
24 | },
25 | }))
26 |
27 | try:
28 | # When MineCraft sends a message (e.g. on player chat), print it.
29 | async for msg in websocket:
30 | msg = json.loads(msg)
31 | print(json.dumps(msg, indent=2))
32 | except websockets.exceptions.ConnectionClosedError:
33 | print('Disconnected from MineCraft')
34 |
35 | def main():
36 | global EVENT_TYPE
37 | parser = argparse.ArgumentParser("Minecraft websocket subscriber")
38 | parser.add_argument("--host", default="localhost", help="host to listen on, default localhost")
39 | parser.add_argument("--port", default=8000, help="port to listen on, default 8000")
40 | parser.add_argument("--event", default=EVENT_TYPE, help="event type to subscript to, defauly 'PlayerMessage'")
41 | args = parser.parse_args()
42 | EVENT_TYPE = args.event
43 |
44 | start_server = websockets.serve(mineproxy, host=args.host, port=args.port)
45 | print(f'Ready. On MineCraft, type /connect {args.host}:{args.port}')
46 |
47 | asyncio.get_event_loop().run_until_complete(start_server)
48 | asyncio.get_event_loop().run_forever()
49 |
50 | if __name__ == "__main__":
51 | main()
52 |
--------------------------------------------------------------------------------
/siemcraft_addon_behavior/scripts/server/server_scriptapi.js:
--------------------------------------------------------------------------------
1 | var system = server.registerSystem(0,0);
2 |
3 | system.initialize = function() {
4 | this.listenForEvent("minecraft:entity_death", (eventData) => this.onEntityDeath(eventData));
5 | };
6 |
7 | // Helper function to tell as message to be picked up by
8 | // the websocket in a 'PlayerMessage' event
9 | system.sendMessage = function (message) {
10 | let ExecuteEventData = this.createEventData("minecraft:execute_command");
11 | ExecuteEventData.data.command = "/tell @a \"" + message + "\"";
12 | this.broadcastEvent("minecraft:execute_command", ExecuteEventData);
13 | };
14 |
15 | system.onEntityDeath = function (eventData) {
16 | // Only look for entities killed by the player
17 | if (eventData.data.killer.__identifier__ != "minecraft:player") {
18 | return;
19 | }
20 | // Only look for entities killed with a name
21 | let killed_name = this.getComponent(eventData.data.entity, "minecraft:nameable");
22 | if (killed_name == null) {
23 | return;
24 | }
25 |
26 | // Get weapon in main hand, assume it was what was used to kill it
27 | let handContainer = system.getComponent(eventData.data.killer, "minecraft:hand_container");
28 | let mainHandItem = handContainer.data[0];
29 |
30 | // If there was a projectile, get that projectile_type
31 | let projectile = ""
32 | if (eventData.data.projectile_type != null && eventData.data.projectile_type !== "undefined") {
33 | projectile = eventData.data.projectile_type
34 | }
35 |
36 | // Get the raw event JSON we saved as a tag
37 | let tags = system.getComponent(eventData.data.entity, "minecraft:tag");
38 | if (tags == null) {
39 | return;
40 | }
41 |
42 | let eventb64 = tags.data[0];
43 | var prefix = "[SIEMCRAFT]";
44 | if (!eventb64.startsWith(prefix)) {
45 | return;
46 | }
47 | eventb64 = eventb64.slice(prefix.length);
48 |
49 | // Send message as a JSON string
50 | let message = prefix + '{"eventb64": "' + eventb64 + '",\n"item":"' + mainHandItem.item + '",\n"projectile": "' + projectile + '"}'
51 | this.sendMessage(message);
52 | };
53 |
--------------------------------------------------------------------------------
/src/main.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import (
4 | "flag"
5 | "fmt"
6 | "os"
7 | "os/signal"
8 | "syscall"
9 | )
10 |
11 | var channels stringSet
12 |
13 | func main() { os.Exit(mainReturnWithCode()) }
14 | func mainReturnWithCode() int {
15 | rulesDir := flag.String("rules", ".\\rules", "Folder containing SIGMA rules")
16 | bindAddress := flag.String("bind", "127.0.0.1", "Address to bind websocket to")
17 | bindPort := flag.String("port", "8000", "Port to bind websocket to")
18 | fakeEvents := flag.Bool("fakeEvents", false, "Don't subscript to event logs, just fake generate them")
19 | noKill := flag.Bool("noKill", false, "Never attempt to kill a process")
20 | flag.Var(&channels, "channels", "Comma-seperated list of event logs to subscribe to\n(default [\"Microsoft-Windows-Sysmon/Operational\", \"Security\"])")
21 | flag.Parse()
22 |
23 | // Set default channels if none specified
24 | if len(channels) == 0 {
25 | channels = append(channels, []string{"Microsoft-Windows-Sysmon/Operational", "Security"}...)
26 | }
27 |
28 | // Load SIGMA rules
29 | err := ParseRules(*rulesDir)
30 | if err != nil {
31 | fmt.Printf("[*] Error Parsing Rules: %s\n", err.Error())
32 | return 1
33 | }
34 |
35 | if *fakeEvents {
36 | // Just fake them, and don't kill
37 | *noKill = true
38 | FireFakeEvents()
39 | } else {
40 | // Start getting events from Event logs
41 | err = StartEventSubscription(channels)
42 | if err != nil {
43 | fmt.Printf("[*] Error Starting Event Subscription: %s\n", err.Error())
44 | return 2
45 | }
46 | defer StopEventSubscription()
47 | }
48 |
49 | // Start Minecraft websocket to handle requests
50 | err = StartMinecraftWebsocket(*bindAddress, *bindPort, *noKill)
51 | if err != nil {
52 | fmt.Printf("[*] Error Starting Minecraft websocket: %s\n", err.Error())
53 | return 1
54 | }
55 | return 0
56 | }
57 |
58 | func init() {
59 | c := make(chan os.Signal)
60 | // This works on Windows, weird...
61 | signal.Notify(c, os.Interrupt, syscall.SIGTERM)
62 | go func() {
63 | <-c
64 | // Ensure we cleanup as we quit
65 | StopEventSubscription()
66 | os.Exit(0)
67 | }()
68 | }
69 |
--------------------------------------------------------------------------------
/.github/workflows/release.yml:
--------------------------------------------------------------------------------
1 | name: Publish Release
2 |
3 | on:
4 | push:
5 | tags:
6 | - 'v*' # Push events to matching v*, i.e. v1.0, v20.15.10
7 |
8 |
9 | jobs:
10 | build:
11 | runs-on: windows-latest
12 | steps:
13 | - name: Checkout code
14 | uses: actions/checkout@v2
15 | with:
16 | submodules: recursive
17 |
18 | - name: Install Go
19 | uses: actions/setup-go@v2
20 | with:
21 | go-version: '1.17.6'
22 |
23 | - name: Build binary
24 | run: go build -o .\bin\siemcraft.exe ./src
25 |
26 | - name: Build Behavior addon
27 | run: Compress-Archive -Path .\siemcraft_addon_behavior -DestinationPath .\bin\siemcraft_addon_behavior.mcpack -Force
28 |
29 | - name: Build Resource addon
30 | run: Compress-Archive -Path .\siemcraft_addon_resource -DestinationPath .\bin\siemcraft_addon_resource.mcpack -Force
31 |
32 | - name: Build GeteTest addon
33 | run: Compress-Archive -Path .\siemcraft_addon_gametest -DestinationPath .\bin\siemcraft_addon_gametest.mcpack -Force
34 |
35 | - name: Package addon
36 | run: Compress-Archive -Path .\bin\*.mcpack -DestinationPath .\bin\siemcraft.mcaddon -Force
37 |
38 | - name: Create release
39 | id: create_release
40 | uses: actions/create-release@v1
41 | env:
42 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
43 | with:
44 | tag_name: ${{ github.ref }}
45 | release_name: Release ${{ github.ref }}
46 | draft: false
47 | prerelease: false
48 |
49 | - name: Upload binary
50 | uses: actions/upload-release-asset@v1
51 | env:
52 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
53 | with:
54 | upload_url: ${{ steps.create_release.outputs.upload_url }}
55 | asset_path: ./bin/siemcraft.exe
56 | asset_name: siemcraft.exe
57 | asset_content_type: application/octet-stream
58 |
59 | - name: Upload addon
60 | uses: actions/upload-release-asset@v1
61 | env:
62 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
63 | with:
64 | upload_url: ${{ steps.create_release.outputs.upload_url }}
65 | asset_path: ./bin/siemcraft.mcaddon
66 | asset_name: siemcraft.mcaddon
67 | asset_content_type: application/octet-stream
68 |
--------------------------------------------------------------------------------
/src/eventlogger.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import (
4 | "encoding/json"
5 | "errors"
6 | "fmt"
7 | "strconv"
8 | "strings"
9 | "sync"
10 |
11 | "github.com/0xrawsec/golang-win32/win32/wevtapi"
12 | "github.com/bradleyjkemp/sigma-go"
13 | "golang.org/x/sys/windows"
14 | )
15 |
16 | var waitGroup sync.WaitGroup
17 | var eventProvider *wevtapi.PullEventProvider = nil
18 |
19 | type SealighterMessage struct {
20 | Header map[string]interface{} `json:"header"`
21 | Properties map[string]interface{} `json:"properties"`
22 | PropertyTypes map[string]interface{} `json:"property_types"`
23 | }
24 |
25 | func IsAdmin() (bool, error) {
26 | // Check if current process has privliges
27 | // to get event logs as a fail-fast
28 | var token windows.Token
29 | err := windows.OpenProcessToken(
30 | windows.CurrentProcess(),
31 | windows.TOKEN_QUERY,
32 | &token,
33 | )
34 | if err != nil {
35 | return false, err
36 | }
37 |
38 | return token.IsElevated(), nil
39 | }
40 |
41 | func StartEventSubscription(channels []string) error {
42 | fmt.Println("[e] Starting event subscription")
43 |
44 | // Only run if user is Elevated
45 | isAdmin, err := IsAdmin()
46 | if err != nil {
47 | return err
48 | }
49 | if !isAdmin {
50 | return errors.New("getting Event logs requires elevation")
51 | }
52 |
53 | fmt.Printf("[e] Subscribing to Event Log channels:\n")
54 | for _, channel := range channels {
55 | fmt.Printf("[e] - %s\n", channel)
56 | }
57 |
58 | // Creat waitGroup to keep track of goroutine
59 | waitGroup = sync.WaitGroup{}
60 | eventProvider = wevtapi.NewPullEventProvider()
61 | waitGroup.Add(1)
62 | go func() {
63 | // Make a call to wevtapi to subscive to event log channels
64 | fetchFlags := wevtapi.EvtSubscribeToFutureEvents
65 | for e := range eventProvider.FetchEvents(channels, fetchFlags) {
66 | // Check event against SIGMA rules
67 | j := e.ToJSONEvent()
68 | event := j.Event.EventData
69 | channel := strings.ToLower(j.Event.System.Channel)
70 | var rule *sigma.Rule
71 |
72 | // Add fields that Sigma might want to check
73 | event["Computer"] = j.Event.System.Computer
74 | event["EventID"] = j.Event.System.EventID
75 | event["Provider_Name"] = j.Event.System.Provider.Name
76 |
77 | if channel == "application" || channel == "security" || channel == "system" {
78 | // Check standard Event Log Channels
79 | rule, err = CheckRules(event, channel)
80 | if err != nil {
81 | continue
82 | }
83 | } else if strings.Contains(channel, "sealighter") {
84 | // Need to convert event to be like Sysmon
85 | message := SealighterMessage{}
86 | err := json.Unmarshal([]byte(event["json"]), &message)
87 | if err != nil {
88 | continue
89 | }
90 |
91 | // For now only add the 'Properties' and not the ETW Header
92 | for k, v := range message.Properties {
93 | // Rename 'ImageFileName' to 'Image'
94 | // to match with Sysmon
95 | if k == "ImageFileName" {
96 | k = "Image"
97 | v = fmt.Sprintf("\\%s", v)
98 | }
99 | event[k] = fmt.Sprint(v)
100 | }
101 | // Delete the json string as we no longet need it
102 | delete(event, "json")
103 |
104 | // Now we can check the rule
105 | // First check if there's any sealighter specific
106 | // SIGMA rules (unlikley), then if not assume a process-creation
107 | // event
108 | rule, err = CheckRules(event, "sealighter")
109 | if err != nil {
110 | continue
111 | }
112 | if rule == nil {
113 | rule, err = CheckRules(event, "process_creation")
114 | if err != nil {
115 | continue
116 | }
117 | }
118 | } else {
119 | // Otherwise assume Sysmon
120 | channel = "sysmon"
121 | eventID, err := strconv.Atoi(j.Event.System.EventID)
122 | if err != nil {
123 | continue
124 | }
125 | switch eventID {
126 | case 1:
127 | // Process
128 | rule, err = CheckRules(event, "process_creation")
129 | if err != nil {
130 | return
131 | }
132 | default:
133 | // Unhandled event type
134 | continue
135 | }
136 | }
137 |
138 | // If a match, raise alert in Minecraft
139 | if rule != nil {
140 | // Remove fields we don't need to see in Minecraft
141 | delete(event, "EventID")
142 | delete(event, "Provider_Name")
143 | RaiseAlert(event, rule, channel)
144 | }
145 | }
146 | waitGroup.Done()
147 | }()
148 |
149 | return nil
150 | }
151 |
152 | func StopEventSubscription() {
153 | if eventProvider != nil {
154 | fmt.Println("[e] Stopping event subscription")
155 | eventProvider.Stop()
156 | waitGroup.Wait()
157 | }
158 | }
159 |
--------------------------------------------------------------------------------
/src/rules.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import (
4 | "context"
5 | "errors"
6 | "fmt"
7 | "io/ioutil"
8 | "math/rand"
9 | "os"
10 | "path/filepath"
11 | "strings"
12 | "time"
13 |
14 | "github.com/bradleyjkemp/sigma-go"
15 | "github.com/bradleyjkemp/sigma-go/evaluator"
16 | )
17 |
18 | var RuleCategories []string = []string{"application", "security", "system", "process_creation", "file_create", "image_load", "driver_load", "network_connection", "dns", "registry_event", "sealighter"}
19 | var Rules map[string][]sigma.Rule
20 |
21 | func checkRule(event map[string]string, category string, rule sigma.Rule) (evaluator.Result, error) {
22 | // Sigma-Go uses runtime panics for things like "unsupported modifier re"
23 | defer func() { recover() }()
24 |
25 | ruleEvaluator := evaluator.ForRule(rule)
26 | result, err := ruleEvaluator.Matches(context.Background(), event)
27 | if err != nil {
28 | fmt.Printf("Failed to evaluate rule: %s", err.Error())
29 | return evaluator.Result{Match: false}, err
30 | }
31 | return result, nil
32 | }
33 |
34 | func CheckRules(event map[string]string, category string) (*sigma.Rule, error) {
35 | for _, rule := range Rules[category] {
36 | // Check rule, handle runtime panics from library
37 | result, err := checkRule(event, category, rule)
38 | if err != nil {
39 | return nil, err
40 | }
41 |
42 | if result.Match {
43 | return &rule, nil
44 | }
45 | }
46 | return nil, nil
47 | }
48 |
49 | func ParseRules(rulesDir string) error {
50 | fmt.Printf("[r] Parsing SIGMA rules from: %s\n", rulesDir)
51 |
52 | // Create global rules slice
53 | Rules = make(map[string][]sigma.Rule, len(RuleCategories))
54 | for _, category := range RuleCategories {
55 | Rules[category] = make([]sigma.Rule, 0, 10)
56 | }
57 | ruleCount := 0
58 |
59 | // Get rules from directory
60 | err := filepath.Walk(rulesDir, func(path string, info os.FileInfo, err error) error {
61 | if err != nil {
62 | return err
63 | }
64 | if !info.IsDir() {
65 | contents, err := ioutil.ReadFile(path)
66 | if err != nil {
67 | fmt.Printf("Failed to open rule %s: %s\n", path, err.Error())
68 | return nil
69 | }
70 | rule, err := sigma.ParseRule(contents)
71 | if err != nil {
72 | fmt.Printf("Failed to parse rule %s: %s\n", path, err.Error())
73 | return nil
74 | }
75 | // Only Windows rules count
76 | if rule.Logsource.Product != "windows" {
77 | return nil
78 | }
79 |
80 | // Rules either have a Service or a Category
81 | ruleType := strings.TrimSpace(rule.Logsource.Service + rule.Logsource.Category)
82 | if ruleType == "dns_query" {
83 | ruleType = "dns"
84 | }
85 | switch ruleType {
86 | case
87 | // Services
88 | "application",
89 | "security",
90 | "system",
91 | // Categories
92 | "process_creation",
93 | "file_create",
94 | "image_load",
95 | "driver_load",
96 | "network_connection",
97 | "dns",
98 | "registry_event":
99 | //
100 | fmt.Printf("[r] Found rule: %s\n", rule.Title)
101 | Rules[ruleType] = append(Rules[ruleType], rule)
102 | ruleCount++
103 | default:
104 | fmt.Printf("Ignoring Rule for bad service/category: %s\n", rule.Title)
105 | }
106 | }
107 | return nil
108 | })
109 | if err != nil {
110 | return err
111 | }
112 |
113 | // Only run if we have at least one valid rule
114 | if ruleCount == 0 {
115 | errString := fmt.Sprintf("No valid rules found in %s", rulesDir)
116 | return errors.New(errString)
117 | }
118 | fmt.Printf("[r] Number of rules found: %d\n", ruleCount)
119 | return nil
120 | }
121 |
122 | // Used for Debugging only
123 | func FireFakeEvents() {
124 | // First get a list of all the rules
125 | allRules := make([]sigma.Rule, 0)
126 | for _, category := range RuleCategories {
127 | for _, rule := range Rules[category] {
128 | // Overwrite category (which we don't use)
129 | // for our own purposes
130 | rule.Logsource.Category = category
131 | allRules = append(allRules, rule)
132 | }
133 | }
134 |
135 | // Get list of possible fake values
136 | selfImage, _ := os.Executable()
137 | imageNames := []string{
138 | "C:\\Windows\\System32\\whoami.exe",
139 | "C:\\Windows\\System32\\lsass.exe",
140 | "C:\\Windows\\System32\\svchost.exe",
141 | "C:\\Windows\\System32\\cmd.exe",
142 | "C:\\Windows\\System32\\powershell.exe",
143 | "C:\\Windows\\System32\\inetsrv\\w3wp.exe",
144 | "C:\\Python27\\python.exe",
145 | "C:\\dodgy\\mimikatz.exe",
146 | "C:\\bonza\\netcat.exe",
147 | "C\\Program Files (x86)\\Microsoft Office\\Office14\\WINWORD.EXE",
148 | selfImage,
149 | }
150 | commandLines := []string{
151 | "",
152 | "",
153 | "",
154 | "/c echo [*]& pwd & echo [*]",
155 | "-ep bypass -window hidden -enc 'AAA='",
156 | "dpapi::masterkey",
157 | "-k netsvcs -p -s Schedule",
158 | "-c 'print(\"hyper\")'",
159 | "-lvp 8000",
160 | }
161 | users := []string{
162 | "PATHDOWS\\PATH",
163 | "PATHDOWS\\DODGY",
164 | "NT AUTHORITY\\SYSTEM",
165 | "LocalService",
166 | "NetworkService",
167 | "Guest",
168 | }
169 |
170 | fmt.Printf("[f] Faking event generation\n")
171 | go func() {
172 | for {
173 | // Only fire events if there are players
174 | rand.Seed(time.Now().UnixNano())
175 | if len(MinecraftPlayers) != 0 {
176 | image := getRandom(imageNames)
177 | parentImage := getRandom(imageNames)
178 | event := map[string]string{
179 | "ProcessId": "-1",
180 | "Image": image,
181 | "CommandLine": fmt.Sprintf("%s %s", image, getRandom(commandLines)),
182 | "User": getRandom(users),
183 | "UtcTime": time.Now().Format("2006-01-02 15:04:05.000"),
184 | "ParentProcessId": "-1",
185 | "ParentImage": parentImage,
186 | "ParentCommandLine": fmt.Sprintf("%s %s", parentImage, getRandom(commandLines)),
187 | "Computer": "PATHDOWS",
188 | }
189 | rule := allRules[rand.Intn(len(allRules))]
190 | RaiseAlert(event, &rule, rule.Logsource.Category)
191 | }
192 | time.Sleep(time.Duration(rand.Intn(15)) * time.Second)
193 | }
194 | }()
195 | }
196 |
--------------------------------------------------------------------------------
/siemcraft_addon_behavior/entities/chicken.json:
--------------------------------------------------------------------------------
1 | {
2 | "format_version": "1.16.0",
3 | "minecraft:entity": {
4 | "description": {
5 | "identifier": "minecraft:chicken",
6 | "is_spawnable": true,
7 | "is_summonable": true,
8 | "is_experimental": false
9 | },
10 | "component_groups": {
11 | "minecraft:chicken_baby": {
12 | "minecraft:is_baby": {
13 | },
14 | "minecraft:scale": {
15 | "value":0.5
16 | },
17 | "minecraft:ageable": {
18 | "duration": 1200,
19 | "feed_items": [
20 | "wheat_seeds",
21 | "beetroot_seeds",
22 | "melon_seeds",
23 | "pumpkin_seeds"
24 | ],
25 | "grow_up": {
26 | "event": "minecraft:ageable_grow_up",
27 | "target": "self"
28 | }
29 | },
30 | "minecraft:behavior.follow_parent": {
31 | "priority": 5,
32 | "speed_multiplier": 1.1
33 | }
34 | },
35 |
36 | "minecraft:chicken_adult": {
37 | "minecraft:experience_reward": {
38 | "on_bred": "Math.Random(1,7)",
39 | "on_death": "query.last_hit_by_player ? Math.Random(1,3) : 0"
40 | },
41 | "minecraft:loot": {
42 | "table": "loot_tables/entities/chicken.json"
43 | },
44 | "minecraft:breedable": {
45 | "require_tame": false,
46 | "breeds_with": {
47 | "mate_type": "minecraft:chicken",
48 | "baby_type": "minecraft:chicken",
49 | "breed_event": {
50 | "event": "minecraft:entity_born",
51 | "target": "baby"
52 | }
53 | },
54 | "breed_items": [
55 | "wheat_seeds",
56 | "beetroot_seeds",
57 | "melon_seeds",
58 | "pumpkin_seeds"
59 | ]
60 | },
61 | "minecraft:behavior.breed": {
62 | "priority": 3,
63 | "speed_multiplier": 1.0
64 | },
65 | "minecraft:rideable": {
66 | "seat_count": 1,
67 | "family_types": [
68 | "zombie"
69 | ],
70 | "seats": {
71 | "position": [ 0.0, 0.4, 0.0 ]
72 | }
73 | },
74 | "minecraft:spawn_entity": {
75 | "entities": {
76 | "min_wait_time": 300,
77 | "max_wait_time": 600,
78 | "spawn_sound": "plop",
79 | "spawn_item": "egg",
80 | "filters": {
81 | "test": "rider_count", "subject": "self", "operator": "==", "value": 0
82 | }
83 | }
84 | }
85 | }
86 | },
87 |
88 | "components": {
89 | "minecraft:is_hidden_when_invisible": {
90 | },
91 | "minecraft:type_family": {
92 | "family": [ "chicken", "mob" ]
93 | },
94 | "minecraft:breathable": {
95 | "total_supply": 15,
96 | "suffocate_time": 0
97 | },
98 | "minecraft:collision_box": {
99 | "width": 0.6,
100 | "height": 0.8
101 | },
102 | "minecraft:nameable": {
103 | "alwaysShow": true
104 | },
105 | "minecraft:health": {
106 | "value": 4,
107 | "max": 4
108 | },
109 | "minecraft:hurt_on_condition": {
110 | "damage_conditions": [
111 | {
112 | "filters": { "test": "in_lava", "subject": "self", "operator": "==", "value": true },
113 | "cause": "lava",
114 | "damage_per_tick": 4
115 | }
116 | ]
117 | },
118 | "minecraft:movement": {
119 | "value": 0.25
120 | },
121 | "minecraft:damage_sensor": {
122 | "triggers": [
123 | {
124 | "cause": "fall",
125 | "deals_damage": false
126 | },
127 | {
128 | "on_damage": {
129 | "filters": {
130 | "all_of": [
131 | { "test": "has_damage", "value": "fatal" },
132 | { "test": "is_family", "subject": "other", "value": "player" },
133 | { "none_of": { "test": "has_equipment", "domain": "hand", "subject": "other", "value": "diamond_sword"} }
134 | ]
135 | },
136 | "event": "special_death_event",
137 | "target": "self"
138 | }
139 | },
140 | {
141 | "on_damage": {
142 | "filters": {
143 | "all_of": [
144 | { "test": "has_damage", "value": "fatal" },
145 | { "test": "is_family", "subject": "other", "value": "player" },
146 | { "test": "has_equipment", "domain": "hand", "subject": "other", "value": "diamond_sword"}
147 | ]
148 | },
149 | "event": "special_death_event_diamond",
150 | "target": "self"
151 | }
152 | }
153 | ]
154 | },
155 | "minecraft:leashable": {
156 | "soft_distance": 4.0,
157 | "hard_distance": 6.0,
158 | "max_distance": 10.0
159 | },
160 | "minecraft:balloonable": {
161 | "mass": 0.5
162 | },
163 | "minecraft:navigation.walk": {
164 | "can_path_over_water": true,
165 | "avoid_damage_blocks": true
166 | },
167 | "minecraft:movement.basic": {
168 | },
169 | "minecraft:jump.static": {
170 | },
171 | "minecraft:can_climb": {
172 | },
173 | "minecraft:despawn": {
174 | "despawn_from_distance": {}
175 | },
176 | "minecraft:behavior.float": {
177 | "priority": 0
178 | },
179 | "minecraft:behavior.panic": {
180 | "priority": 1,
181 | "speed_multiplier": 1.5
182 | },
183 | "minecraft:behavior.mount_pathing": {
184 | "priority": 2,
185 | "speed_multiplier": 1.5,
186 | "target_dist": 0.0,
187 | "track_target": true
188 | },
189 | "minecraft:behavior.tempt": {
190 | "priority": 4,
191 | "speed_multiplier": 1.0,
192 | "items": [
193 | "wheat_seeds",
194 | "beetroot_seeds",
195 | "melon_seeds",
196 | "pumpkin_seeds"
197 | ]
198 | },
199 | "minecraft:behavior.random_stroll": {
200 | "priority": 6,
201 | "speed_multiplier": 1.0
202 | },
203 | "minecraft:behavior.look_at_player": {
204 | "priority": 7,
205 | "look_distance": 6.0,
206 | "probability": 0.02
207 | },
208 | "minecraft:behavior.random_look_around": {
209 | "priority": 8
210 | },
211 | "minecraft:physics": {
212 | },
213 | "minecraft:pushable": {
214 | "is_pushable": true,
215 | "is_pushable_by_piston": true
216 | },
217 | "minecraft:conditional_bandwidth_optimization": {
218 | }
219 | },
220 |
221 | "events": {
222 | "special_death_event": { },
223 | "special_death_event_diamond": { },
224 | "from_egg": {
225 | "add": { "component_groups": [ "minecraft:chicken_baby" ] }
226 | },
227 |
228 | "minecraft:entity_spawned": {
229 | "randomize": [
230 | {
231 | "weight": 95,
232 | "trigger": "minecraft:spawn_adult"
233 | },
234 | {
235 | "weight": 5,
236 | "add": {
237 | "component_groups": [
238 | "minecraft:chicken_baby"
239 | ]
240 | }
241 | }
242 | ]
243 | },
244 |
245 | "minecraft:entity_born": {
246 | "remove": {
247 | },
248 | "add": {
249 | "component_groups": [
250 | "minecraft:chicken_baby"
251 | ]
252 | }
253 | },
254 |
255 | "minecraft:ageable_grow_up": {
256 | "remove": {
257 | "component_groups": [
258 | "minecraft:chicken_baby"
259 | ]
260 | },
261 | "add": {
262 | "component_groups": [
263 | "minecraft:chicken_adult"
264 | ]
265 | }
266 | },
267 |
268 | "minecraft:spawn_adult": {
269 | "add": {
270 | "component_groups": [
271 | "minecraft:chicken_adult"
272 | ]
273 | }
274 | }
275 | }
276 | }
277 | }
--------------------------------------------------------------------------------
/siemcraft_addon_behavior/entities/cow.json:
--------------------------------------------------------------------------------
1 | {
2 | "format_version": "1.16.0",
3 | "minecraft:entity": {
4 | "description": {
5 | "identifier": "minecraft:cow",
6 | "is_spawnable": true,
7 | "is_summonable": true,
8 | "is_experimental": false
9 | },
10 | "component_groups": {
11 | "minecraft:cow_baby": {
12 | "minecraft:is_baby": {
13 | },
14 | "minecraft:scale": {
15 | "value":0.5
16 | },
17 | "minecraft:ageable": {
18 | "duration": 1200,
19 | "feed_items": "wheat",
20 | "grow_up": {
21 | "event": "minecraft:ageable_grow_up",
22 | "target": "self"
23 | }
24 | },
25 |
26 | "minecraft:behavior.follow_parent": {
27 | "priority": 6,
28 | "speed_multiplier": 1.1
29 | }
30 | },
31 |
32 | "minecraft:cow_adult": {
33 | "minecraft:experience_reward": {
34 | "on_bred": "Math.Random(1,7)",
35 | "on_death": "query.last_hit_by_player ? Math.Random(1,3) : 0"
36 | },
37 | "minecraft:loot": {
38 | "table": "loot_tables/entities/cow.json"
39 | },
40 | "minecraft:behavior.breed": {
41 | "priority": 3,
42 | "speed_multiplier": 1.0
43 | },
44 | "minecraft:breedable": {
45 | "require_tame": false,
46 | "breed_items": "wheat",
47 | "breeds_with": {
48 | "mate_type": "minecraft:cow",
49 | "baby_type": "minecraft:cow",
50 | "breed_event": {
51 | "event": "minecraft:entity_born",
52 | "target": "baby"
53 | }
54 | }
55 | },
56 | "minecraft:interact": {
57 | "interactions": [
58 | {
59 | "on_interact": {
60 | "filters": {
61 | "all_of": [
62 | { "test": "is_family", "subject" : "other", "value" : "player"},
63 | { "test": "has_equipment", "domain": "hand", "subject": "other", "value": "bucket:0"}
64 | ]
65 | }
66 | },
67 | "use_item": true,
68 | "transform_to_item": "bucket:1",
69 | "play_sounds": "milk",
70 | "interact_text": "action.interact.milk"
71 | }
72 | ]
73 | }
74 | }
75 | },
76 |
77 | "components": {
78 | "minecraft:damage_sensor": {
79 | "triggers": [
80 | {
81 | "on_damage": {
82 | "filters": {
83 | "all_of": [
84 | { "test": "has_damage", "value": "fatal" },
85 | { "test": "is_family", "subject": "other", "value": "player" },
86 | { "none_of": { "test": "has_equipment", "domain": "hand", "subject": "other", "value": "diamond_sword"} }
87 | ]
88 | },
89 | "event": "special_death_event",
90 | "target": "self"
91 | }
92 | },
93 | {
94 | "on_damage": {
95 | "filters": {
96 | "all_of": [
97 | { "test": "has_damage", "value": "fatal" },
98 | { "test": "is_family", "subject": "other", "value": "player" },
99 | { "test": "has_equipment", "domain": "hand", "subject": "other", "value": "diamond_sword"}
100 | ]
101 | },
102 | "event": "special_death_event_diamond",
103 | "target": "self"
104 | }
105 | }
106 | ]
107 | },
108 | "minecraft:is_hidden_when_invisible": {
109 | },
110 | "minecraft:type_family": {
111 | "family": [ "cow", "mob" ]
112 | },
113 | "minecraft:breathable": {
114 | "total_supply": 15,
115 | "suffocate_time": 0
116 | },
117 | "minecraft:navigation.walk": {
118 | "can_path_over_water": true,
119 | "avoid_water": true,
120 | "avoid_damage_blocks": true
121 | },
122 | "minecraft:movement.basic": {
123 |
124 | },
125 | "minecraft:jump.static": {
126 | },
127 | "minecraft:can_climb": {
128 | },
129 | "minecraft:collision_box": {
130 | "width": 0.9,
131 | "height": 1.3
132 | },
133 | "minecraft:nameable": {
134 | "alwaysShow": true
135 | },
136 | "minecraft:health": {
137 | "value": 10,
138 | "max": 10
139 | },
140 | "minecraft:hurt_on_condition": {
141 | "damage_conditions": [
142 | {
143 | "filters": {
144 | "test": "in_lava",
145 | "subject": "self",
146 | "operator": "==",
147 | "value": true
148 | },
149 | "cause": "lava",
150 | "damage_per_tick": 4
151 | }
152 | ]
153 | },
154 | "minecraft:movement": {
155 | "value": 0.25
156 | },
157 | "minecraft:despawn": {
158 | "despawn_from_distance": {}
159 | },
160 | "minecraft:behavior.float": {
161 | "priority": 0
162 | },
163 | "minecraft:behavior.panic": {
164 | "priority": 1,
165 | "speed_multiplier": 1.25
166 | },
167 | "minecraft:behavior.mount_pathing": {
168 | "priority": 2,
169 | "speed_multiplier": 1.5,
170 | "target_dist": 0.0,
171 | "track_target": true
172 | },
173 | "minecraft:behavior.breed": {
174 | "priority": 3,
175 | "speed_multiplier": 1.0
176 | },
177 | "minecraft:behavior.tempt": {
178 | "priority": 4,
179 | "speed_multiplier": 1.25,
180 | "items": [
181 | "wheat"
182 | ]
183 | },
184 | "minecraft:behavior.follow_parent": {
185 | "priority": 5,
186 | "speed_multiplier": 1.1
187 | },
188 | "minecraft:behavior.random_stroll": {
189 | "priority": 6,
190 | "speed_multiplier": 0.8
191 | },
192 | "minecraft:behavior.look_at_player": {
193 | "priority": 7,
194 | "look_distance": 6.0,
195 | "probability": 0.02
196 | },
197 | "minecraft:behavior.random_look_around": {
198 | "priority": 9
199 | },
200 | "minecraft:leashable": {
201 | "soft_distance": 4.0,
202 | "hard_distance": 6.0,
203 | "max_distance": 10.0
204 | },
205 | "minecraft:balloonable": {
206 | },
207 | "minecraft:rideable": {
208 | "seat_count": 1,
209 | "family_types": [
210 | "zombie"
211 | ],
212 | "seats": {
213 | "position": [ 0.0, 1.105, 0.0 ]
214 | }
215 | },
216 | "minecraft:physics": {
217 | },
218 | "minecraft:pushable": {
219 | "is_pushable": true,
220 | "is_pushable_by_piston": true
221 | },
222 | "minecraft:conditional_bandwidth_optimization": {
223 | }
224 | },
225 |
226 | "events": {
227 | "special_death_event": { },
228 | "special_death_event_diamond": { },
229 | "minecraft:entity_spawned": {
230 | "randomize": [
231 | {
232 | "weight": 95,
233 | "trigger": "minecraft:spawn_adult"
234 | },
235 | {
236 | "weight": 5,
237 | "add": {
238 | "component_groups": [
239 | "minecraft:cow_baby"
240 | ]
241 | }
242 | }
243 | ]
244 | },
245 |
246 | "minecraft:entity_born": {
247 | "add": {
248 | "component_groups": [
249 | "minecraft:cow_baby"
250 | ]
251 | }
252 | },
253 |
254 | "minecraft:entity_transformed": {
255 | "remove": {
256 | },
257 | "add": {
258 | "component_groups": [
259 | "minecraft:cow_adult"
260 | ]
261 | }
262 | },
263 |
264 | "minecraft:ageable_grow_up": {
265 | "remove": {
266 | "component_groups": [
267 | "minecraft:cow_baby"
268 | ]
269 | },
270 | "add": {
271 | "component_groups": [
272 | "minecraft:cow_adult"
273 | ]
274 | }
275 | },
276 |
277 | "minecraft:spawn_adult": {
278 | "add": {
279 | "component_groups": [
280 | "minecraft:cow_adult"
281 | ]
282 | }
283 | }
284 | }
285 | }
286 | }
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | 
2 |
3 | **SIEMCraft - Security Information and Event Management in Minecraft**
4 |
5 | (please do not take this serioussly, for more information read [this blog post](https://blog.tofile.dev/2022/06/10/siemcraft.html))
6 |
7 | Inspired by [Kubecraftadmin](https://github.com/erjadi/kubecraftadmin), this project allows you to monitor
8 | and detect intrusions across your entire Windows domain, while still mining mad diamond.
9 |
10 | 
11 |
12 | Also see [this demo video](https://youtu.be/8Vyf8Y5wcRY) of SIEMCRAFT in VR.
13 |
14 | - [How it works](#how-it-works)
15 | - [Event Log collecter](#event-log-collecter)
16 | - [SIGMA Rule detection engine](#sigma-rule-detection-engine)
17 | - [Entity generator](#entity-generator)
18 | - [Player action responder](#player-action-responder)
19 | - [How it works - diagram](#how-it-works---diagram)
20 | - [Building](#building)
21 | - [Binary Controller](#binary-controller)
22 | - [Minecraft Addons](#minecraft-addons)
23 | - [Rules](#rules)
24 | - [Installing](#installing)
25 | - [Controller](#controller)
26 | - [Addons](#addons)
27 | - [Running](#running)
28 | - [Controller](#controller-1)
29 | - [Addons](#addons-1)
30 | - [Why would you make this?](#why-would-you-make-this)
31 |
32 | # How it works
33 | SIEMCRAFT is a project that combines a standalone executable 'controller', with a Minecraft addon, designed to
34 | enable a person to manage and respond to security alerts from within Minecraft. The project has a
35 | number of elements:
36 | ## Event Log collecter
37 | Using [RawSec's Win32 library](https://github.com/0xrawsec/golang-win32), SIEMCraft subscribes to
38 | various Windows Event logs, to collect events from
39 | - Microsoft Sysmon
40 | - ETW (via [Sealighter](https://github.com/pathtofile/Sealighter))
41 | - Security, System, and Applicaiton Event logs
42 |
43 | Using Windows Event Forwarding (WEF), you can have SIEMCRAFT run from the central machine and collect
44 | event from an entire Windows Domain
45 |
46 | ## SIGMA Rule detection engine
47 | SIEMCraft will then run events through a user-supplied list of [SIGMA](https://github.com/SigmaHQ/sigma) detection rules
48 | using [Bradley Kemp's library](https://github.com/bradleyjkemp/sigma-go), to detect supsicious and malicious activity within the raw events. Using SigmaHQ's ruleset is also supported
49 |
50 | ## Entity generator
51 | If a rule detects suspicious behaviour, it will trigger the creation of new entity within a person's Minecraft server,
52 | nearby to the player. This entity will display information about:
53 | - The name of the rule triggered
54 | - The Machine name the rule was triggered on
55 | - The user responsible for the process that triggered the rule
56 | - The Image, CommandLine, and PID of the Process
57 | - The Image and PID of the Parent Process
58 | - Other relevant information
59 |
60 | Different types of entities are created depending on the detection severity:
61 | - Low: Chicken
62 | - Medium: Pig or Cow
63 | - High: [Spider, Panda, or Bear](https://adversary.crowdstrike.com/en-US/adversary/cozy-bear/)
64 |
65 | ## Player action responder
66 | If the entity is killed by a player weilding a `Diamond Sword`, SIEMCRAFT will then kill either the process or the parent process, so long as the process image is one of
67 | - cmd.exe
68 | - pwsh.exe
69 | - powershell.exe
70 | - wword.exe
71 |
72 | If the entity is killed by any other means the event is silently dismissed.
73 |
74 | # How it works - diagram
75 | 
76 |
77 |
78 | # Building
79 | You can grab pre-built artefacts from the [releases](https://github.com/pathtofile/siemcraft/releases) page.
80 |
81 | Otherwise, there are two parts to build:
82 | ## Binary Controller
83 | ```bash
84 | go build -o siemcraft.exe ./src
85 | ```
86 |
87 | ## Minecraft Addons
88 | There are three Minecraft addons, a 'behaviour' pack and an 'entity' pack. Packs are just ZIPs, and can be combined
89 | into a single `.mcaddon` ZIP for extra portability:
90 | ```powershell
91 | # Windows
92 | Compress-Archive -Path "siemcraft_addon_behavior" -DestinationPath "siemcraft_addon_behavior.mcpack" -Force
93 | Compress-Archive -Path "siemcraft_addon_resource" -DestinationPath "siemcraft_addon_resource.mcpack" -Force
94 | Compress-Archive -Path "siemcraft_addon_gametest" -DestinationPath "siemcraft_addon_gametest.mcpack" -Force
95 | Compress-Archive -Path "*.mcpack -DestinationPath" "siemcraft.mcaddon" -Force
96 |
97 | # Linux
98 | zip -r siemcraft_addon_behavior.mcpack siemcraft_addon_behavior
99 | zip -r siemcraft_addon_resource.mcpack siemcraft_addon_resource
100 | zip -r siemcraft_addon_gametest.mcpack siemcraft_addon_gametest
101 | zip -r siemcraft_addon_resource.mcaddon *.mcpack
102 | ```
103 |
104 | ## Rules
105 | You will also need some SIGMA rules for SIEMCRAFT to comapre raw events to.
106 | Either use the ones in this repository's [rules directory](rules/), or use
107 | [SIGMA's community rules](https://github.com/SigmaHQ/sigma). Note not all of these rules work with SIEMCRAFT
108 | (see [this](https://github.com/bradleyjkemp/sigma-go/issues/9) discussion).
109 |
110 | # Installing
111 | ## Controller
112 | Place the siemcraft binary anywhere on the machine where the event logs are being generated (usually the same
113 | machine as minecraft).
114 |
115 | ## Addons
116 | To install the Minecraft addon, double-click on the `.mcpack` from the machine with the Minecraft client.
117 | This should install all packs, which you can confirm by clicking `Settings` in Minecraft:
118 | 
119 |
120 | # Running
121 | ## Controller
122 | Start the SIEMCRAFT controller binary from an elevated prompt, giving it the path to the folder containing the SIGMA rules:
123 | ```powershell
124 | $> siemcraft.exe --rules .\rules
125 | [r] Parsing SIGMA rules from: .\rules
126 | [r] Found rule: Security Logon
127 | [r] Found rule: Where Execution
128 | [r] Found rule: Whoami Execution
129 | [r] Number of rules found: 3
130 | [e] Starting event subscription
131 | [e] Subscribing to Event Log channels:
132 | [e] - Microsoft-Windows-Sysmon/Operational
133 | [e] - Security
134 | [m] starting SIEMCraft, run this command to connect:
135 | /connect 127.0.0.1:8000/ws
136 | ```
137 |
138 | Siemcraft accepts the following commandline options:
139 | ```
140 | -bind string
141 | Address to bind websocket to (default "127.0.0.1")
142 | -channels value
143 | Comma-seperated list of event logs to subscribe to
144 | (default ["Microsoft-Windows-Sysmon/Operational", "Security"])
145 | -fakeEvents
146 | Don't subscript to event logs, just fake generate them
147 | -noKill
148 | Never attempt to kill a process
149 | -port string
150 | Port to bind websocket to (default "8000")
151 | -rules string
152 | Folder containing SIGMA rules (default ".\\rules")
153 | ```
154 |
155 | ## Addons
156 | First, if running SIEMCRAFT on the same local host as the Minecraft client, you need to allow Minecraft to
157 | talk to your local network. Run this in an elevated PowerShell:
158 | ```powershell
159 | # First find the "Package Family Name" of Minecraft, which should look like like 'microsoft.minecraftuwp_RANDOM_STRING'
160 | $family_name=(Get-AppxPackage '*minecraft*').PackageFamilyName
161 |
162 | # Enable minecraft to reach loopback network
163 | cmd.exe /C "checknetisolation loopbackexempt -a -n=$family_name"
164 |
165 | # Check it worked, you should see minecraft here
166 | checknetisolation loopbackexempt -s
167 | ```
168 |
169 | Next, create a new Minecraft world with the following options:
170 | - All cheats and experiments enabled (including GameTest), and achievements turned off
171 | - All the SIEMCRAFT 'Resource' and 'Behaviour' packs activated
172 |
173 | 
174 | 
175 |
176 | Once the Map is created, open up the console and type this command to connect
177 | to the SIEMCRAFT controller
178 | ```
179 | /connect :/ws
180 | ```
181 |
182 | By default the IP Address and port are:
183 | ```
184 | /connect 127.0.0.1:8000/ws
185 | ```
186 |
187 | 
188 |
189 | You should see positive output in both the Minecraft UI and in the Controller's output.
190 |
191 | # Why would you make this?
192 | See [the blog post](https://blog.tofile.dev/2022/06/10/siemcraft.html), but tl;dr is because I'm an idiot who was bored.
193 | I also presented this "work" at a local security meetup, you can see the slides [here](/assets/diamond_talk_sharable.pdf)
194 | (but the blog has more info, and the talk wasn't recorded).
195 |
--------------------------------------------------------------------------------
/siemcraft_addon_behavior/entities/bear.json:
--------------------------------------------------------------------------------
1 | {
2 | "format_version": "1.16.0",
3 | "minecraft:entity": {
4 | "description": {
5 | "identifier": "siemcraft:bear",
6 | "is_spawnable": true,
7 | "is_summonable": true,
8 | "is_experimental": false
9 | },
10 |
11 | "component_groups": {
12 | "minecraft:baby": {
13 | "minecraft:is_baby": {
14 | },
15 | "minecraft:scale": {
16 | "value": 0.5
17 | },
18 | "minecraft:ageable": {
19 | "duration": 1200,
20 | "grow_up": {
21 | "event": "minecraft:ageable_grow_up",
22 | "target": "self"
23 | }
24 | },
25 |
26 | "minecraft:behavior.follow_parent": {
27 | "priority": 4,
28 | "speed_multiplier": 1.25
29 | }
30 | },
31 |
32 | "minecraft:baby_wild": {
33 | "minecraft:on_target_acquired": {
34 | "event": "minecraft:on_scared",
35 | "target": "self"
36 | },
37 | "minecraft:behavior.nearest_attackable_target": {
38 | "priority": 4,
39 | "entity_types": [
40 | {
41 | "filters": { "test" : "is_family", "subject" : "other", "value" : "player"},
42 | "max_dist": 16
43 | }
44 | ]
45 | }
46 | },
47 |
48 | "minecraft:baby_scared": {
49 | "minecraft:angry": {
50 | "duration": 1,
51 | "broadcast_anger": true,
52 | "broadcast_range": 41,
53 | "calm_event": {
54 | "event": "minecraft:baby_on_calm",
55 | "target": "self"
56 | }
57 | }
58 | },
59 |
60 | "minecraft:adult": {
61 | "minecraft:experience_reward": {
62 | "on_death": "query.last_hit_by_player ? Math.Random(1,3) : 0"
63 | },
64 | "minecraft:loot": {
65 | "table": "loot_tables/entities/polar_bear.json"
66 | }
67 | },
68 |
69 | "minecraft:adult_wild": {
70 | "minecraft:on_target_acquired": {
71 | "event": "minecraft:on_anger",
72 | "target": "self"
73 | },
74 | "minecraft:on_friendly_anger": {
75 | "event": "minecraft:on_anger",
76 | "target": "self"
77 | },
78 | "minecraft:behavior.nearest_attackable_target": {
79 | "priority": 4,
80 | "entity_types": [
81 | {
82 | "filters": {
83 | "test": "is_family",
84 | "subject": "other",
85 | "value": "player"
86 | },
87 | "max_dist": 16
88 | }
89 | ],
90 | "must_see": false
91 | }
92 | },
93 |
94 | "minecraft:adult_hostile": {
95 | "minecraft:attack": {
96 | "damage": 6.0
97 | },
98 | "minecraft:angry": {
99 | "duration": 500,
100 | "broadcast_anger": false,
101 | "broadcast_range": 20,
102 | "calm_event": {
103 | "event": "minecraft:on_calm",
104 | "target": "self"
105 | }
106 | },
107 |
108 | "minecraft:behavior.stomp_attack": {
109 | "priority": 1,
110 | "track_target": true,
111 | "require_complete_path": true,
112 | "stomp_range_multiplier": 2.0,
113 | "no_damage_range_multiplier": 2.0
114 | }
115 | }
116 | },
117 |
118 | "components": {
119 | "minecraft:damage_sensor": {
120 | "triggers": [
121 | {
122 | "on_damage": {
123 | "filters": {
124 | "all_of": [
125 | { "test": "has_damage", "value": "fatal" },
126 | { "test": "is_family", "subject": "other", "value": "player" }
127 | ]
128 | },
129 | "event": "special_death_event",
130 | "target": "self"
131 | }
132 | }
133 | ]
134 | },
135 | "minecraft:is_hidden_when_invisible": {
136 | },
137 | "minecraft:type_family": {
138 | "family": [ "polarbear", "bear", "mob" ]
139 | },
140 | "minecraft:breathable": {
141 | "total_supply": 15,
142 | "suffocate_time": 0
143 | },
144 | "minecraft:nameable": {
145 | "alwaysShow": true
146 | },
147 | "minecraft:health": {
148 | "value": 30
149 | },
150 | "minecraft:hurt_on_condition": {
151 | "damage_conditions": [
152 | {
153 | "filters": { "test": "in_lava", "subject": "self", "operator": "==", "value": true },
154 | "cause": "lava",
155 | "damage_per_tick": 4
156 | }
157 | ]
158 | },
159 | "minecraft:collision_box": {
160 | "width": 1.3,
161 | "height": 1.4
162 | },
163 | "minecraft:movement": {
164 | "value": 0.25
165 | },
166 | "minecraft:water_movement": {
167 | "drag_factor": 0.98
168 | },
169 | "minecraft:navigation.walk": {
170 | "can_path_over_water": true,
171 | "avoid_damage_blocks": true
172 | },
173 | "minecraft:movement.basic": {
174 |
175 | },
176 | "minecraft:jump.static": {
177 | },
178 | "minecraft:can_climb": {
179 | },
180 | "minecraft:follow_range": {
181 | "value": 48
182 | },
183 | "minecraft:despawn": {
184 | "despawn_from_distance": {}
185 | },
186 | "minecraft:behavior.float": {
187 | "priority": 0
188 | },
189 | "minecraft:behavior.hurt_by_target": {
190 | "priority": 1
191 | },
192 | "minecraft:behavior.random_stroll": {
193 | "priority": 5
194 | },
195 | "minecraft:behavior.look_at_player": {
196 | "priority": 6,
197 | "target_distance": 6.0,
198 | "probability": 0.02
199 | },
200 | "minecraft:behavior.random_look_around": {
201 | "priority": 7
202 | },
203 | "minecraft:physics": {
204 | },
205 | "minecraft:pushable": {
206 | "is_pushable": true,
207 | "is_pushable_by_piston": true
208 | },
209 | "minecraft:behavior.panic": {
210 | "priority": 2,
211 | "speed_multiplier": 2.0
212 | },
213 | "minecraft:leashable": {
214 | "soft_distance": 4.0,
215 | "hard_distance": 6.0,
216 | "max_distance": 10.0
217 | },
218 | "minecraft:conditional_bandwidth_optimization": {
219 | }
220 | },
221 |
222 | "events": {
223 | "special_death_event": { },
224 | "special_death_event_diamond": { },
225 | "minecraft:entity_spawned": {
226 | "randomize": [
227 | {
228 | "weight": 9,
229 | "add": {
230 | "component_groups": [
231 | "minecraft:adult",
232 | "minecraft:adult_wild",
233 | "minecraft:adult_hostile"
234 | ]
235 | }
236 | },
237 | {
238 | "weight": 1,
239 | "add": {
240 | "component_groups": [
241 | "minecraft:baby",
242 | "minecraft:baby_wild"
243 | ]
244 | }
245 | }
246 | ]
247 | },
248 |
249 | "minecraft:entity_born": {
250 | "add": {
251 | "component_groups": [
252 | "minecraft:baby",
253 | "minecraft:baby_wild"
254 | ]
255 | }
256 | },
257 |
258 | "minecraft:ageable_grow_up": {
259 | "remove": {
260 | "component_groups": [
261 | "minecraft:baby",
262 | "minecraft:baby_wild",
263 | "minecraft:baby_scared"
264 | ]
265 | },
266 | "add": {
267 | "component_groups": [
268 | "minecraft:adult",
269 | "minecraft:adult_wild",
270 | "minecraft:adult_hostile"
271 | ]
272 | }
273 | },
274 |
275 | "minecraft:on_calm": {
276 | },
277 |
278 | "minecraft:on_anger": {
279 | "remove": {
280 | "component_groups": [
281 | "minecraft:adult_wild"
282 | ]
283 | },
284 | "add": {
285 | "component_groups": [
286 | "minecraft:adult_hostile"
287 | ]
288 | }
289 | },
290 |
291 | "minecraft:baby_on_calm": {
292 | "remove": {
293 | "component_groups": [
294 | "minecraft:baby_scared"
295 | ]
296 | },
297 | "add": {
298 | "component_groups": [
299 | "minecraft:baby_wild"
300 | ]
301 | }
302 | },
303 |
304 | "minecraft:on_scared": {
305 | "remove": {
306 | "component_groups": [
307 | "minecraft:baby_wild"
308 | ]
309 | },
310 | "add": {
311 | "component_groups": [
312 | "minecraft:baby_scared"
313 | ]
314 | }
315 | }
316 | }
317 | }
318 | }
319 |
--------------------------------------------------------------------------------
/siemcraft_addon_behavior/entities/pig.json:
--------------------------------------------------------------------------------
1 | {
2 | "format_version": "1.16.0",
3 | "minecraft:entity": {
4 | "description": {
5 | "identifier": "minecraft:pig",
6 | "is_spawnable": true,
7 | "is_summonable": true,
8 | "is_experimental": false
9 | },
10 | "component_groups": {
11 | "minecraft:pig_baby": {
12 | "minecraft:is_baby": {
13 | },
14 | "minecraft:scale": {
15 | "value": 0.5
16 | },
17 | "minecraft:ageable": {
18 | "duration": 1200,
19 | "feed_items": [ "carrot", "beetroot", "potato" ],
20 | "grow_up": {
21 | "event": "minecraft:ageable_grow_up",
22 | "target": "self"
23 | }
24 | },
25 |
26 | "minecraft:behavior.follow_parent": {
27 | "priority": 6,
28 | "speed_multiplier": 1.1
29 | }
30 | },
31 |
32 | "minecraft:pig_transform": {
33 | "minecraft:transformation": {
34 | "into": "minecraft:pig_zombie",
35 | "delay": 0.5
36 | }
37 | },
38 |
39 | "minecraft:pig_adult": {
40 | "minecraft:experience_reward": {
41 | "on_bred": "Math.Random(1,7)",
42 | "on_death": "query.last_hit_by_player ? Math.Random(1,3) : 0"
43 | },
44 | "minecraft:loot": {
45 | "table": "loot_tables/entities/pig.json"
46 | },
47 | "minecraft:behavior.breed": {
48 | "priority": 4,
49 | "speed_multiplier": 1.0
50 | },
51 | "minecraft:breedable": {
52 | "require_tame": false,
53 | "breeds_with": {
54 | "mate_type": "minecraft:pig",
55 | "baby_type": "minecraft:pig",
56 | "breed_event": {
57 | "event": "minecraft:entity_born",
58 | "target": "baby"
59 | }
60 | },
61 | "breed_items": [ "carrot", "beetroot", "potato" ]
62 | }
63 | },
64 |
65 | "minecraft:pig_unsaddled": {
66 | "minecraft:interact": {
67 | "interactions": [
68 | {
69 | "on_interact": {
70 | "filters": { "test": "has_equipment", "subject": "other", "domain": "hand", "value": "saddle"},
71 | "event": "minecraft:on_saddled"
72 | },
73 | "use_item": true,
74 | "play_sounds": "saddle",
75 | "interact_text": "action.interact.saddle"
76 | }
77 | ]
78 | },
79 | "minecraft:rideable": {
80 | "seat_count": 1,
81 | "family_types": [
82 | "zombie"
83 | ],
84 | "seats": {
85 | "position": [ 0.0, 0.63, 0.0 ]
86 | }
87 | }
88 | },
89 |
90 | "minecraft:pig_saddled": {
91 | "minecraft:is_saddled": {
92 | },
93 | "minecraft:loot": {
94 | "table": "loot_tables/entities/pig_saddled.json"
95 | },
96 | "minecraft:boostable": {
97 | "speed_multiplier": 2.0,
98 | "duration": 3.0,
99 | "boost_items": [
100 | {
101 | "item": "carrotOnAStick",
102 | "damage": 2,
103 | "replace_item": "fishing_rod"
104 | }
105 | ]
106 | },
107 | "minecraft:rideable": {
108 | "seat_count": 1,
109 | "interact_text": "action.interact.mount",
110 | "family_types": [
111 | "player"
112 | ],
113 | "seats": {
114 | "position": [ 0.0, 0.63, 0.0 ]
115 | }
116 | },
117 | "minecraft:item_controllable": {
118 | "control_items": "carrotOnAStick"
119 | },
120 | "minecraft:behavior.controlled_by_player": {
121 | "priority": 0
122 | }
123 | }
124 | },
125 |
126 |
127 | "components": {
128 | "minecraft:is_hidden_when_invisible": {
129 | },
130 | "minecraft:damage_sensor": {
131 | "triggers": [
132 | {
133 | "on_damage": {
134 | "filters": [
135 | {
136 | "test": "is_family",
137 | "subject": "other",
138 | "value": "lightning"
139 | },
140 | {
141 | "test": "is_difficulty",
142 | "operator": "!=",
143 | "value": "peaceful"
144 | }
145 | ],
146 | "event": "become_zombie"
147 | },
148 | "deals_damage": false
149 | },
150 | {
151 | "on_damage": {
152 | "filters": {
153 | "all_of": [
154 | { "test": "has_damage", "value": "fatal" },
155 | { "test": "is_family", "subject": "other", "value": "player" },
156 | { "none_of": { "test": "has_equipment", "domain": "hand", "subject": "other", "value": "diamond_sword"} }
157 | ]
158 | },
159 | "event": "special_death_event",
160 | "target": "self"
161 | }
162 | },
163 | {
164 | "on_damage": {
165 | "filters": {
166 | "all_of": [
167 | { "test": "has_damage", "value": "fatal" },
168 | { "test": "is_family", "subject": "other", "value": "player" },
169 | { "test": "has_equipment", "domain": "hand", "subject": "other", "value": "diamond_sword"}
170 | ]
171 | },
172 | "event": "special_death_event_diamond",
173 | "target": "self"
174 | }
175 | }
176 | ]
177 | },
178 | "minecraft:type_family": {
179 | "family": [ "pig", "mob" ]
180 | },
181 | "minecraft:breathable": {
182 | "total_supply": 15,
183 | "suffocate_time": 0
184 | },
185 | "minecraft:nameable": {
186 | "alwaysShow": true
187 | },
188 | "minecraft:health": {
189 | "value": 10,
190 | "max": 10
191 | },
192 | "minecraft:hurt_on_condition": {
193 | "damage_conditions": [
194 | {
195 | "filters": { "test": "in_lava", "subject": "self", "operator": "==", "value": true },
196 | "cause": "lava",
197 | "damage_per_tick": 4
198 | }
199 | ]
200 | },
201 | "minecraft:movement": {
202 | "value": 0.25
203 | },
204 | "minecraft:navigation.walk": {
205 | "can_path_over_water": true,
206 | "avoid_water": true,
207 | "avoid_damage_blocks": true
208 | },
209 | "minecraft:movement.basic": {
210 |
211 | },
212 | "minecraft:jump.static": {
213 | },
214 | "minecraft:can_climb": {
215 | },
216 | "minecraft:collision_box": {
217 | "width": 0.9,
218 | "height": 0.9
219 | },
220 | "minecraft:leashable": {
221 | "soft_distance": 4.0,
222 | "hard_distance": 6.0,
223 | "max_distance": 10.0
224 | },
225 | "minecraft:balloonable": {
226 | "mass": 0.75
227 | },
228 | "minecraft:despawn": {
229 | "despawn_from_distance": {}
230 | },
231 | "minecraft:behavior.mount_pathing": {
232 | "priority": 1,
233 | "speed_multiplier": 1.25,
234 | "target_dist": 0.0,
235 | "track_target": true
236 | },
237 | "minecraft:behavior.float": {
238 | "priority": 2
239 | },
240 | "minecraft:behavior.panic": {
241 | "priority": 3,
242 | "speed_multiplier": 1.25
243 | },
244 | "minecraft:behavior.tempt": {
245 | "priority": 5,
246 | "speed_multiplier": 1.2,
247 | "items": [
248 | "potato",
249 | "carrot",
250 | "beetroot",
251 | "carrotOnAStick"
252 | ]
253 | },
254 | "minecraft:behavior.random_stroll": {
255 | "priority": 7,
256 | "speed_multiplier": 1.0
257 | },
258 | "minecraft:behavior.look_at_player": {
259 | "priority": 8,
260 | "look_distance": 6.0,
261 | "probability": 0.02
262 | },
263 | "minecraft:behavior.random_look_around": {
264 | "priority": 9
265 | },
266 | "minecraft:physics": {
267 | },
268 | "minecraft:pushable": {
269 | "is_pushable": true,
270 | "is_pushable_by_piston": true
271 | },
272 | "minecraft:conditional_bandwidth_optimization": {
273 | }
274 | },
275 |
276 |
277 | "events": {
278 | "special_death_event": { },
279 | "special_death_event_diamond": { },
280 | "become_zombie": {
281 | "remove": {
282 | },
283 | "add": {
284 | "component_groups": [
285 | "minecraft:pig_transform"
286 | ]
287 | }
288 | },
289 | "minecraft:entity_spawned": {
290 | "randomize": [
291 | {
292 | "weight": 95,
293 | "trigger": "minecraft:spawn_adult"
294 | },
295 | {
296 | "weight": 5,
297 | "remove": {
298 | },
299 | "add": {
300 | "component_groups": [
301 | "minecraft:pig_baby"
302 | ]
303 |
304 | }
305 | }
306 | ]
307 | },
308 |
309 | "minecraft:entity_born": {
310 | "remove": {
311 | },
312 | "add": {
313 | "component_groups": [
314 | "minecraft:pig_baby"
315 | ]
316 | }
317 | },
318 |
319 | "minecraft:ageable_grow_up": {
320 | "remove": {
321 | "component_groups": [
322 | "minecraft:pig_baby"
323 | ]
324 | },
325 | "add": {
326 | "component_groups": [
327 | "minecraft:pig_adult",
328 | "minecraft:pig_unsaddled"
329 | ]
330 | }
331 | },
332 |
333 | "minecraft:on_saddled": {
334 | "remove": {
335 | "component_groups": [
336 | "minecraft:pig_unsaddled"
337 | ]
338 | },
339 | "add": {
340 | "component_groups": [
341 | "minecraft:pig_saddled"
342 | ]
343 | }
344 | },
345 | "minecraft:spawn_adult": {
346 | "add": {
347 | "component_groups": [
348 | "minecraft:pig_adult",
349 | "minecraft:pig_unsaddled"
350 | ]
351 | }
352 | }
353 | }
354 | }
355 | }
356 |
--------------------------------------------------------------------------------
/src/minecraft.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import (
4 | "bytes"
5 | "encoding/base64"
6 | "encoding/json"
7 | "errors"
8 | "fmt"
9 | "math/rand"
10 | "os"
11 | "os/exec"
12 | "strconv"
13 | "strings"
14 | "time"
15 |
16 | "golang.org/x/sync/errgroup"
17 |
18 | "github.com/bradleyjkemp/sigma-go"
19 | "github.com/pathtofile/mcwss"
20 | "github.com/pathtofile/mcwss/protocol/event"
21 | )
22 |
23 | var MinecraftPlayers []*mcwss.Player
24 | var neverKillProcesses bool
25 | var hostname string
26 |
27 | // Used to tag messages from and to MineCraft addon
28 | const messagePrefix = "[SIEMCRAFT]"
29 |
30 | // Sent from the add-on when an entity is killed
31 | type SIEMCraftMessage struct {
32 | // Item used to kill the entity
33 | Item string `json:"item"`
34 | // If a Projectile was used, it'd be here
35 | Projectile string `json:"projectile"`
36 | // The saved event
37 | EventB64 string `json:"eventb64"`
38 | }
39 |
40 | func getRandom(slice []string) string {
41 | return slice[rand.Intn(len(slice))]
42 | }
43 |
44 | func RaiseAlert(event map[string]string, rule *sigma.Rule, channel string) {
45 | // If there's not a player don't do anything
46 | if len(MinecraftPlayers) == 0 {
47 | return
48 | }
49 | fmt.Printf("[m] Rule Hit: %s\n", rule.Title)
50 |
51 | for _, p := range MinecraftPlayers {
52 | actionbar(p, fmt.Sprintf("Rule Hit: %s", rule.Title))
53 | }
54 |
55 | // Seed randomness for entity spawning
56 | rand.Seed(time.Now().UnixNano())
57 |
58 | // Select random player to spawn near
59 | player := MinecraftPlayers[rand.Intn(len(MinecraftPlayers))]
60 |
61 | name := ""
62 | jsonTag := ""
63 | if channel == "sysmon" {
64 | // Only display certain feilds
65 | simpleFields := []string{
66 | // Common
67 | "Computer",
68 | "ProcessId",
69 | "Image",
70 | "CommandLine",
71 | "User",
72 | // "UtcTime",
73 | // Process
74 | "ParentProcessId",
75 | "ParentImage",
76 | // "ParentCommandLine",
77 | // Network connection
78 | "SourceIp",
79 | "SourcePort",
80 | "DestinationIp",
81 | "DestinationPort",
82 | // Image and Driver Load
83 | "ImageLoaded",
84 | // File Create
85 | "TargetFilename",
86 | // Registry
87 | "TargetObject",
88 | // DNS
89 | "QueryName",
90 | "QueryStatus",
91 | "QueryResults",
92 | }
93 | simpleEvent := map[string]string{}
94 | for _, field := range simpleFields {
95 | if event[field] != "" {
96 | simpleEvent[field] = strings.ReplaceAll(event[field], "\n", "")
97 | }
98 | }
99 | eventData, _ := json.MarshalIndent(simpleEvent, "", " ")
100 | name = string(eventData)
101 |
102 | // Now store event as a base64 JSON in the entity's tag
103 | evantDataJSON, _ := json.Marshal(simpleEvent)
104 | jsonTag = base64.StdEncoding.EncodeToString(evantDataJSON)
105 | } else {
106 | // For everything else, print full event because I cbf custom parsing everything
107 | eventData, _ := json.MarshalIndent(event, "", " ")
108 | name = string(eventData)
109 |
110 | // Now store event as a base64 JSON in the entity's tag
111 | evantDataJSON, _ := json.Marshal(event)
112 | jsonTag = base64.StdEncoding.EncodeToString(evantDataJSON)
113 | }
114 |
115 | // Remove or escape characters that can't be easily displayed in minecraft
116 | name = strings.ReplaceAll(name, "\\", "\\\\")
117 | name = strings.ReplaceAll(name, "{", "")
118 | name = strings.ReplaceAll(name, "}", "")
119 | name = strings.ReplaceAll(name, "\"", "")
120 |
121 | // Add Rule header
122 | name = fmt.Sprintf("Rule: %s\n----------\n%s", rule.Title, name)
123 |
124 | // The event severity determins the entity spawned
125 | entity := ""
126 | if rule.Level == "low" {
127 | entity = "chicken"
128 | } else if rule.Level == "medium" {
129 | entity = getRandom([]string{"pig", "cow"})
130 | } else if rule.Level == "high" {
131 | entity = getRandom([]string{"spider", "panda", "siemcraft:bear"})
132 | }
133 |
134 | // Generate locations and spawn command
135 | xPos := rand.Intn(18) + 2
136 | zPos := rand.Intn(18) + 2
137 | if rand.Float32() < 0.5 {
138 | xPos = xPos * -1
139 | }
140 | if rand.Float32() < 0.5 {
141 | zPos = zPos * -1
142 | }
143 | fmt.Printf("[m] Spawning %s at %d:%d from player %s\n", entity, xPos, zPos, player.Name())
144 | spawnCmd := fmt.Sprintf("summon %s \"%s\" ~%d ~ ~%d", entity, name, xPos, zPos)
145 | player.Exec(spawnCmd, nil)
146 |
147 | // Add the event as JSON in a tag
148 | // This command selects any un-tagged entity within a small radious of where we jsut summoned it
149 | // (in case it was spawned in the air and has started to fall)
150 | // We have to do these tag shenanigans to select the target, as we can't get a multi-line name
151 | // And we can't rename after the fact (so can't 'summon as simpleName->tag->rename to multiline')
152 | jsonTag = fmt.Sprintf("%s%s", messagePrefix, jsonTag)
153 | tagCmd := fmt.Sprintf("tag @e[tag=,type=%s,x=~%d,y=~,z=~%d,r=50,rm=0] add \"%s\"", entity, xPos, zPos, jsonTag)
154 | player.Exec(tagCmd, nil)
155 |
156 | // Teleport to a safe place, as they may have spawned into the wall
157 | spreadCmd := fmt.Sprintf("spreadplayers ~%d ~%d 0 5 @e[tag=\"%s\"]", xPos, zPos, jsonTag)
158 | player.Exec(spreadCmd, nil)
159 | }
160 |
161 | // actionbar will display a message to the player
162 | func actionbar(player *mcwss.Player, message string) {
163 | player.Exec(fmt.Sprintf("title %s actionbar %s", player.Name(), message), nil)
164 | }
165 |
166 | func onMessage(event *event.PlayerMessage) {
167 | if event.Sender != "Script Engine" || event.Type != "tell" {
168 | return
169 | }
170 | // First trim quotes, then check and trim prefix
171 | msgString := event.Message[1 : len(event.Message)-1]
172 | if !strings.HasPrefix(msgString, messagePrefix) {
173 | return
174 | }
175 | msgString = msgString[len(messagePrefix):]
176 |
177 | // De-serialise from JSON
178 | message := SIEMCraftMessage{}
179 | err := json.Unmarshal([]byte(msgString), &message)
180 | if err != nil {
181 | // Not our message
182 | fmt.Printf("[m] Not our message? %s\n", err.Error())
183 | return
184 | }
185 | // Decode event from base64
186 | eventString, err := base64.StdEncoding.DecodeString(message.EventB64)
187 | if err != nil {
188 | fmt.Printf("[m] Failed to decode Evnet from message: %s\n", err.Error())
189 | return
190 | }
191 | messageEvent := map[string]string{}
192 | err = json.Unmarshal([]byte(eventString), &messageEvent)
193 | if err != nil {
194 | fmt.Printf("[m] Failed to unmarshal event: %s\n", err.Error())
195 | return
196 | }
197 |
198 | // Check Item used to kill, determine if we're killing process
199 | // if neverKillProcesses is set, then also never attempt to kill it
200 | // Also check event is from this machine and not a remote one (i.e. a WEF forwarded event)
201 | if !neverKillProcesses && messageEvent["Computer"] == hostname && strings.Contains(message.Item, "diamond_sword") {
202 | // Diamond weapon, kill a process!
203 |
204 | // kill if image is one of these
205 | killableImages := []string{"cmd.exe", "pwsh.exe", "powershell.exe", "wword.exe"}
206 | pidToKill := 0
207 | for _, killableImage := range killableImages {
208 | if strings.HasSuffix(messageEvent["Image"], killableImage) {
209 | pidToKill, _ = strconv.Atoi(messageEvent["ProcessId"])
210 | fmt.Printf("[*] Killing Pid %d (%s)\n", pidToKill, messageEvent["CommandLine"])
211 | }
212 | }
213 | if pidToKill == 0 {
214 | // Check parent, maybe we can kill it?
215 | for _, killableImage := range killableImages {
216 | if strings.HasSuffix(messageEvent["ParentImage"], killableImage) {
217 | pidToKill, _ = strconv.Atoi(messageEvent["ParentProcessId"])
218 | fmt.Printf("[*] Killing Parent Pid %d (%s)\n", pidToKill, messageEvent["ParentCommandLine"])
219 | }
220 | }
221 | }
222 | // Pid could be < 0 in testing, and 0 if there was no process ID found
223 | if pidToKill <= 0 {
224 | fmt.Printf("[m] Event handled\n")
225 | } else {
226 | process, err := os.FindProcess(pidToKill)
227 | if err != nil {
228 | fmt.Printf("[*] Failed to find process %d: %s\n", pidToKill, err.Error())
229 | return
230 | }
231 | err = process.Kill()
232 | if err != nil {
233 | fmt.Printf("[*] Failed to kill process %d: %s\n", pidToKill, err.Error())
234 | return
235 | }
236 | }
237 | } else {
238 | fmt.Printf("[m] Event handled for PID %s\n", messageEvent["ProcessId"])
239 | }
240 | }
241 |
242 | func onConnection(player *mcwss.Player) {
243 | playerName := player.Name()
244 | fmt.Printf("[m] Player %s has connected\n", playerName)
245 |
246 | // Send welcome message
247 | player.Exec(fmt.Sprintf("title %s title SIEMCraft", playerName), nil)
248 |
249 | // Provide player with equipment
250 | player.Exec("give @s diamond_sword", nil)
251 | player.Exec("give @s netherite_sword", nil)
252 |
253 | // TODO: remove?
254 | player.Exec("time set noon", nil)
255 | player.Exec("weather clear", nil)
256 | player.Exec("alwaysday", nil)
257 |
258 | // Register to recieve messages, we'll
259 | // use them to get data back from minecraft addon
260 | player.OnPlayerMessage(onMessage)
261 |
262 | // Add player
263 | MinecraftPlayers = append(MinecraftPlayers, player)
264 | }
265 |
266 | func onDisconnection(player *mcwss.Player) {
267 | // Log player disconnect
268 | // Find and remove player from list
269 | for i, p := range MinecraftPlayers {
270 | if p == player {
271 | fmt.Printf("[m] Main player %s has disconnected\n", player.Name())
272 | MinecraftPlayers = append(MinecraftPlayers[:i], MinecraftPlayers[i+1:]...)
273 | break
274 | }
275 | }
276 | }
277 |
278 | func setHostName() error {
279 | // Gotta do this the dodgy way
280 | cmd := exec.Command("powershell", "-c", `[System.Net.Dns]::GetHostByName($env:computerName).HostName`)
281 | var out bytes.Buffer
282 | cmd.Stdout = &out
283 | err := cmd.Run()
284 | if err != nil {
285 | return err
286 | }
287 | hostname = strings.TrimSpace(out.String())
288 | return nil
289 | }
290 |
291 | func StartMinecraftWebsocket(bindAddress string, bindPort string, noKill bool) error {
292 | MinecraftPlayers = make([]*mcwss.Player, 0, 5)
293 |
294 | // Create a new server using the default configuration. To use specific configuration, pass a *wss.Config{} in here.
295 | address := fmt.Sprintf("%s:%s", bindAddress, bindPort)
296 | var c = mcwss.Config{HandlerPattern: "/ws", Address: address}
297 | server := mcwss.NewServer(&c)
298 | if server == nil {
299 | return errors.New("failed to create minecraft server config")
300 | }
301 |
302 | neverKillProcesses = noKill
303 | err := setHostName()
304 | if err != nil {
305 | return err
306 | }
307 |
308 | server.OnConnection(onConnection)
309 | server.OnDisconnection(onDisconnection)
310 |
311 | // Start websocket server
312 | fmt.Println("[m] starting SIEMCraft, run this command to connect:")
313 | fmt.Printf(" /connect %s/ws\n", address)
314 | var errorGroup errgroup.Group
315 | errorGroup.Go(func() error {
316 | return server.Run()
317 | })
318 |
319 | // Run forever (or until ctrl+c)
320 | return errorGroup.Wait()
321 | }
322 |
--------------------------------------------------------------------------------
/siemcraft_addon_behavior/entities/spider.json:
--------------------------------------------------------------------------------
1 | {
2 | "format_version": "1.16.0",
3 | "minecraft:entity": {
4 | "description": {
5 | "identifier": "minecraft:spider",
6 | "is_spawnable": true,
7 | "is_summonable": true,
8 | "is_experimental": false
9 | },
10 |
11 |
12 | "component_groups": {
13 | "minecraft:spider_jockey": {
14 | "minecraft:addrider": {
15 | "entity_type": "minecraft:skeleton"
16 | },
17 | "minecraft:rideable": {
18 | "seat_count": 1,
19 | "family_types": [
20 | "skeleton"
21 | ],
22 | "seats": {
23 | "position": [ 0.0, 0.54, 0.0 ]
24 | }
25 | }
26 | },
27 |
28 | "minecraft:spider_stray_jockey": {
29 | "minecraft:addrider": {
30 | "entity_type": "minecraft:skeleton.stray"
31 | },
32 | "minecraft:rideable": {
33 | "seat_count": 1,
34 | "family_types": [
35 | "skeleton"
36 | ],
37 | "seats": {
38 | "position": [ 0.0, 0.54, 0.0 ]
39 | }
40 | }
41 | },
42 |
43 | "minecraft:spider_wither_jockey": {
44 | "minecraft:addrider": {
45 | "entity_type": "minecraft:skeleton.wither"
46 | },
47 | "minecraft:rideable": {
48 | "seat_count": 1,
49 | "family_types": [
50 | "skeleton"
51 | ],
52 | "seats": {
53 | "position": [ 0.0, 0.54, 0.0 ]
54 | }
55 | }
56 | },
57 |
58 | "minecraft:spider_neutral": {
59 | "minecraft:environment_sensor": {
60 | "triggers": {
61 | "filters": {
62 | "test": "is_brightness",
63 | "operator": "<",
64 | "value": 0.49
65 | },
66 | "event": "minecraft:become_hostile"
67 | }
68 | },
69 | "minecraft:on_target_acquired": {
70 | "event": "minecraft:become_angry"
71 | }
72 | },
73 |
74 | "minecraft:spider_hostile": {
75 | "minecraft:on_target_acquired": {
76 | "event": "minecraft:become_angry"
77 | },
78 | "minecraft:behavior.nearest_attackable_target": {
79 | "priority": 2,
80 | "must_see": true,
81 | "attack_interval": 5,
82 | "entity_types": [
83 | {
84 | "filters": {
85 | "any_of": [
86 | {
87 | "test": "is_family",
88 | "subject": "other",
89 | "value": "player"
90 | },
91 | {
92 | "test": "is_family",
93 | "subject": "other",
94 | "value": "snowgolem"
95 | },
96 | {
97 | "test": "is_family",
98 | "subject": "other",
99 | "value": "irongolem"
100 | }
101 | ]
102 | },
103 | "max_dist": 16
104 | }
105 | ]
106 | }
107 | },
108 |
109 | "minecraft:spider_angry": {
110 | "minecraft:angry": {
111 | "duration": 10,
112 | "duration_delta": 3,
113 | "calm_event": {
114 | "event": "minecraft:become_calm",
115 | "target": "self"
116 | }
117 | },
118 | "minecraft:behavior.leap_at_target": {
119 | "priority": 4,
120 | "yd": 0.4,
121 | "must_be_on_ground": false
122 | },
123 | "minecraft:behavior.melee_attack": {
124 | "priority": 3,
125 | "track_target": true,
126 | "reach_multiplier": 0.8
127 | }
128 | }
129 | },
130 |
131 | "components": {
132 | "minecraft:damage_sensor": {
133 | "triggers": [
134 | {
135 | "on_damage": {
136 | "filters": {
137 | "all_of": [
138 | { "test": "has_damage", "value": "fatal" },
139 | { "test": "is_family", "subject": "other", "value": "player" },
140 | { "none_of": { "test": "has_equipment", "domain": "hand", "subject": "other", "value": "diamond_sword"} }
141 | ]
142 | },
143 | "event": "special_death_event",
144 | "target": "self"
145 | }
146 | },
147 | {
148 | "on_damage": {
149 | "filters": {
150 | "all_of": [
151 | { "test": "has_damage", "value": "fatal" },
152 | { "test": "is_family", "subject": "other", "value": "player" },
153 | { "test": "has_equipment", "domain": "hand", "subject": "other", "value": "diamond_sword"}
154 | ]
155 | },
156 | "event": "special_death_event_diamond",
157 | "target": "self"
158 | }
159 | }
160 | ]
161 | },
162 | "minecraft:is_hidden_when_invisible": {
163 | },
164 | "minecraft:experience_reward": {
165 | "on_death": "query.last_hit_by_player ? 5 : 0"
166 | },
167 | "minecraft:nameable": {
168 | "alwaysShow": true
169 | },
170 | "minecraft:type_family": {
171 | "family": [ "spider", "monster", "mob", "arthropod" ]
172 | },
173 | "minecraft:breathable": {
174 | "total_supply": 15,
175 | "suffocate_time": 0
176 | },
177 | "minecraft:loot": {
178 | "table": "loot_tables/entities/spider.json"
179 | },
180 | "minecraft:collision_box": {
181 | "width": 1.4,
182 | "height": 0.9
183 | },
184 | "minecraft:health": {
185 | "value": 16,
186 | "max": 16
187 | },
188 | "minecraft:hurt_on_condition": {
189 | "damage_conditions": [
190 | {
191 | "filters": { "test": "in_lava", "subject": "self", "operator": "==", "value": true },
192 | "cause": "lava",
193 | "damage_per_tick": 4
194 | }
195 | ]
196 | },
197 | "minecraft:movement": {
198 | "value": 0.3
199 | },
200 | "minecraft:navigation.climb": {
201 | "can_path_over_water": true
202 | },
203 | "minecraft:movement.basic": {
204 | },
205 | "minecraft:jump.static": {
206 | },
207 | "minecraft:can_climb": {
208 | },
209 | "minecraft:attack": {
210 | "damage": 3
211 | },
212 | "minecraft:despawn": {
213 | "despawn_from_distance": {}
214 | },
215 | "minecraft:behavior.float": {
216 | "priority": 1
217 | },
218 | "minecraft:behavior.mount_pathing": {
219 | "priority": 5,
220 | "speed_multiplier": 1.25,
221 | "target_dist": 0.0,
222 | "track_target": true
223 | },
224 | "minecraft:behavior.random_stroll": {
225 | "priority": 6,
226 | "speed_multiplier": 0.8
227 | },
228 | "minecraft:behavior.look_at_player": {
229 | "priority": 7,
230 | "look_distance": 6.0,
231 | "probability": 0.02
232 | },
233 | "minecraft:behavior.random_look_around": {
234 | "priority": 7
235 | },
236 | "minecraft:behavior.hurt_by_target": {
237 | "priority": 1
238 | },
239 | "minecraft:rideable": {
240 | "seat_count": 1,
241 | "family_types": [
242 | "zombie"
243 | ],
244 | "seats": {
245 | "position": [ 0.0, 0.54, -0.1 ]
246 | }
247 | },
248 | "minecraft:physics": {
249 | },
250 | "minecraft:pushable": {
251 | "is_pushable": true,
252 | "is_pushable_by_piston": true
253 | },
254 | "minecraft:conditional_bandwidth_optimization": {
255 | }
256 | },
257 |
258 | "events": {
259 | "special_death_event": { },
260 | "special_death_event_diamond": { },
261 | "minecraft:entity_spawned": {
262 | "randomize": [
263 | {
264 | "weight": 1,
265 | "randomize": [
266 | {
267 | "weight": 80,
268 | "filters": {
269 | "all_of": [
270 | {
271 | "test": "is_daytime",
272 | "value": false
273 | },
274 | {
275 | "test": "is_snow_covered",
276 | "value": true
277 | },
278 | {
279 | "test": "is_underground",
280 | "value": false
281 | }
282 | ]
283 | },
284 | "remove": {},
285 | "add": {
286 | "component_groups": [
287 | "minecraft:spider_stray_jockey",
288 | "minecraft:spider_hostile",
289 | "minecraft:spider_angry"
290 | ]
291 | }
292 | },
293 | {
294 | "weight": 80,
295 | "filters": {
296 | "test": "is_biome",
297 | "value": "the_nether"
298 | },
299 | "remove": {},
300 | "add": {
301 | "component_groups": [
302 | "minecraft:spider_wither_jockey",
303 | "minecraft:spider_hostile",
304 | "minecraft:spider_angry"
305 | ]
306 | }
307 | },
308 | {
309 | "weight": 20,
310 | "filters": {
311 | "any_of": [
312 | {
313 | "test": "is_daytime",
314 | "value": false
315 | },
316 | {
317 | "test": "is_underground",
318 | "value": true
319 | }
320 | ]
321 | },
322 | "remove": {},
323 | "add": {
324 | "component_groups": [
325 | "minecraft:spider_jockey",
326 | "minecraft:spider_hostile",
327 | "minecraft:spider_angry"
328 | ]
329 | }
330 | }
331 | ]
332 | },
333 | {
334 | "weight": 99,
335 | "remove": {},
336 | "add": {
337 | "component_groups": [
338 | "minecraft:spider_hostile",
339 | "minecraft:spider_angry"
340 | ]
341 | }
342 | }
343 | ]
344 | },
345 |
346 | "minecraft:become_hostile": {
347 | "remove": {
348 | "component_groups": [
349 | "minecraft:spider_neutral"
350 | ]
351 | },
352 | "add": {
353 | "component_groups": [
354 | "minecraft:spider_hostile"
355 | ]
356 | }
357 | },
358 |
359 | "minecraft:become_neutral": {
360 | "remove": {
361 | "component_groups": [
362 | "minecraft:spider_hostile"
363 | ]
364 | },
365 | "add": {
366 | "component_groups": [
367 | "minecraft:spider_neutral"
368 | ]
369 | }
370 | },
371 |
372 | "minecraft:become_angry": {
373 | "add": {
374 | "component_groups": [
375 | "minecraft:spider_angry"
376 | ]
377 | }
378 | },
379 | "minecraft:become_calm": {
380 | }
381 | }
382 | }
383 | }
384 |
--------------------------------------------------------------------------------
/go.sum:
--------------------------------------------------------------------------------
1 | github.com/0xrawsec/golang-utils v1.1.8 h1:9TzAKzC7+V2IXaV/3Y1aXiUFHeShL3BXcfL6BheAEH0=
2 | github.com/0xrawsec/golang-utils v1.1.8/go.mod h1:DADTtCFY10qXjWmUVhhJqQIZdSweaHH4soYUDEi8mj0=
3 | github.com/0xrawsec/golang-win32 v1.0.10 h1:2/+XrkpOEa9WndZtAWBnvwi+d+paGc5bRWruJx91fmQ=
4 | github.com/0xrawsec/golang-win32 v1.0.10/go.mod h1:XBEh/JhPosCBiqLCoJsyyKF/+EdwbLaGxQOCsqGEMnQ=
5 | github.com/PaesslerAG/gval v1.0.0 h1:GEKnRwkWDdf9dOmKcNrar9EA1bz1z9DqPIO1+iLzhd8=
6 | github.com/PaesslerAG/gval v1.0.0/go.mod h1:y/nm5yEyTeX6av0OfKJNp9rBNj2XrGhAf5+v24IBN1I=
7 | github.com/PaesslerAG/jsonpath v0.1.0/go.mod h1:4BzmtoM/PI8fPO4aQGIusjGxGir2BzcV0grWtFzq1Y8=
8 | github.com/PaesslerAG/jsonpath v0.1.1 h1:c1/AToHQMVsduPAa4Vh6xp2U0evy4t8SWp8imEsylIk=
9 | github.com/PaesslerAG/jsonpath v0.1.1/go.mod h1:lVboNxFGal/VwW6d9JzIy56bUsYAP6tH/x80vjnCseY=
10 | github.com/alecthomas/participle v0.7.1 h1:2bN7reTw//5f0cugJcTOnY/NYZcWQOaajW+BwZB5xWs=
11 | github.com/alecthomas/participle v0.7.1/go.mod h1:HfdmEuwvr12HXQN44HPWXR0lHmVolVYe4dyL6lQ3duY=
12 | github.com/alecthomas/repr v0.0.0-20181024024818-d37bc2a10ba1/go.mod h1:xTS7Pm1pD1mvyM075QCDSRqH6qRLXylzS24ZTpRiSzQ=
13 | github.com/bradleyjkemp/cupaloy/v2 v2.6.0 h1:knToPYa2xtfg42U3I6punFEjaGFKWQRXJwj0JTv4mTs=
14 | github.com/bradleyjkemp/cupaloy/v2 v2.6.0/go.mod h1:bm7JXdkRd4BHJk9HpwqAI8BoAY1lps46Enkdqw6aRX0=
15 | github.com/bradleyjkemp/sigma-go v0.2.8 h1:bMU0BVgMlT4rYEuPUJKWe+KhKiM+wgLUhj/oNE9wH6A=
16 | github.com/bradleyjkemp/sigma-go v0.2.8/go.mod h1:eDT0OXQD6U68UQXw4XXaRz38Lb/PwJ/BKVCaPQ0I5fA=
17 | github.com/davecgh/go-spew v0.0.0-20161028175848-04cdfd42973b/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
18 | github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
19 | github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
20 | github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
21 | github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
22 | github.com/fsnotify/fsnotify v1.4.9 h1:hsms1Qyu0jgnwNXIxa+/V/PDsU6CfLf6CNO8H7IWoS4=
23 | github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ=
24 | github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE=
25 | github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
26 | github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8=
27 | github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA=
28 | github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs=
29 | github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w=
30 | github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0=
31 | github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
32 | github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
33 | github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
34 | github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
35 | github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
36 | github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
37 | github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
38 | github.com/google/uuid v1.1.0 h1:Jf4mxPC/ziBnoPIdpQdPJ9OeiomAUHLvxmPRSPH9m4s=
39 | github.com/google/uuid v1.1.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
40 | github.com/gorilla/websocket v1.4.0 h1:WDFjx/TMzVgy9VdMMQi2K2Emtwi2QcUQsztZ/zLaH/Q=
41 | github.com/gorilla/websocket v1.4.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ=
42 | github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
43 | github.com/kr/fs v0.1.0/go.mod h1:FFnZGqtBN9Gxj7eW1uZ42v5BccTP0vu6NEaFoC2HwRg=
44 | github.com/mattn/go-colorable v0.1.12 h1:jF+Du6AlPIjs2BiUiQlKOX0rt3SujHxPnksPKZbaA40=
45 | github.com/mattn/go-colorable v0.1.12/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4=
46 | github.com/mattn/go-isatty v0.0.14 h1:yVuAays6BHfxijgZPzw+3Zlu5yQgKGP2/hcQbHb7S9Y=
47 | github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94=
48 | github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A=
49 | github.com/nxadm/tail v1.4.8 h1:nPr65rt6Y5JFSKQO7qToXr7pePgD6Gwiw05lkbyAQTE=
50 | github.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU=
51 | github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
52 | github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk=
53 | github.com/onsi/ginkgo v1.16.4/go.mod h1:dX+/inL/fNMqNlz0e9LfyB9TswhZpCVdJM/Z6Vvnwo0=
54 | github.com/onsi/ginkgo v1.16.5 h1:8xi0RTUf59SOSfEtZMvwTvXYMzG4gV23XVHOZiXNtnE=
55 | github.com/onsi/ginkgo v1.16.5/go.mod h1:+E8gABHa3K6zRBolWtd+ROzc/U5bkGt0FwiG042wbpU=
56 | github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY=
57 | github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo=
58 | github.com/onsi/gomega v1.17.0 h1:9Luw4uT5HTjHTN8+aNcSThgH1vdXnmdJ8xIfZ4wyTRE=
59 | github.com/onsi/gomega v1.17.0/go.mod h1:HnhC7FXeEQY45zxNK3PPoIUhzk/80Xly9PcubAlGdZY=
60 | github.com/pathtofile/mcwss v1.2.2 h1:/ycn7jynzvXYKkuJnMpCB7BnFtnpxF2ATle9ApH2EXs=
61 | github.com/pathtofile/mcwss v1.2.2/go.mod h1:96gBP5tbFM6LpSGZB3TzFxiptbrIAo5E23Dl+tJ8wqc=
62 | github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
63 | github.com/pkg/sftp v1.10.0/go.mod h1:NxmoDg/QLVWluQDUYG7XBZTLUpKeFa8e3aMf1BfjyHk=
64 | github.com/pmezard/go-difflib v0.0.0-20151028094244-d8ed2627bdf0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
65 | github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
66 | github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
67 | github.com/sanity-io/litter v1.3.0/go.mod h1:5Z71SvaYy5kcGtyglXOC9rrUi3c1E8CamFWjQsazTh0=
68 | github.com/sergi/go-diff v1.0.0 h1:Kpca3qRNrduNnOQeazBd0ysaKrUJiIuISHxogkT9RPQ=
69 | github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo=
70 | github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
71 | github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
72 | github.com/stretchr/testify v0.0.0-20161117074351-18a02ba4a312/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
73 | github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
74 | github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
75 | github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
76 | github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY=
77 | github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
78 | github.com/yudai/gojsondiff v1.0.0 h1:27cbfqXLVEJ1o8I6v3y9lg8Ydm53EKqHXAOMxEGlCOA=
79 | github.com/yudai/gojsondiff v1.0.0/go.mod h1:AY32+k2cwILAkW1fbgxQ5mUmMiZFgLIV+FBNExI05xg=
80 | github.com/yudai/golcs v0.0.0-20170316035057-ecda9a501e82 h1:BHyfKlQyqbsFN5p3IfnEUduWvb9is428/nNb5L3U01M=
81 | github.com/yudai/golcs v0.0.0-20170316035057-ecda9a501e82/go.mod h1:lgjkn3NuSvDfVJdfcVVdX+jpBxNmX4rDAzaS45IcYoM=
82 | github.com/yudai/pp v2.0.1+incompatible h1:Q4//iY4pNF6yPLZIigmvcl7k/bPgrcTPIFIcmawg5bI=
83 | github.com/yudai/pp v2.0.1+incompatible/go.mod h1:PuxR/8QJ7cyCkFp/aUDS+JY727OFEZkTdatxwunjIkc=
84 | github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
85 | golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
86 | golang.org/x/crypto v0.0.0-20190621222207-cc06ce4a13d4/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
87 | golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
88 | golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
89 | golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
90 | golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
91 | golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
92 | golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
93 | golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
94 | golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
95 | golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
96 | golang.org/x/net v0.0.0-20210428140749-89ef3d95e781 h1:DzZ89McO9/gWPsQXS/FVKAlG02ZjaQ6AlZRBimEYOd0=
97 | golang.org/x/net v0.0.0-20210428140749-89ef3d95e781/go.mod h1:OJAsFXCWl8Ukc7SiCT/9KSuxbyM7479/AVlXFRxuMCk=
98 | golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
99 | golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
100 | golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
101 | golang.org/x/sync v0.0.0-20210220032951-036812b2e83c h1:5KslGYwFpkhGh+Q16bwMP3cOontH8FOep7tGV86Y7SQ=
102 | golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
103 | golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
104 | golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
105 | golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
106 | golang.org/x/sys v0.0.0-20190626150813-e07cf5db2756/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
107 | golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
108 | golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
109 | golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
110 | golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
111 | golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
112 | golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
113 | golang.org/x/sys v0.0.0-20210112080510-489259a85091/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
114 | golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
115 | golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
116 | golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6 h1:foEbQz/B0Oz6YIqu/69kfXPYeFQAuuMYFkjaqXzl5Wo=
117 | golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
118 | golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
119 | golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
120 | golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
121 | golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
122 | golang.org/x/text v0.3.6 h1:aRYxNxv6iGQlyVaZmk6ZgYEDa+Jg18DxebPSrd6bg1M=
123 | golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
124 | golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
125 | golang.org/x/tools v0.0.0-20190320215829-36c10c0a621f/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
126 | golang.org/x/tools v0.0.0-20190625160430-252024b82959/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
127 | golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
128 | golang.org/x/tools v0.0.0-20201224043029-2b0845dc783e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
129 | golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
130 | golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
131 | golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
132 | golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
133 | google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
134 | google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
135 | google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=
136 | google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE=
137 | google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo=
138 | google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
139 | google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
140 | google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
141 | gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
142 | gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
143 | gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
144 | gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ=
145 | gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=
146 | gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
147 | gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
148 | gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
149 | gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
150 | gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
151 | gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
152 | gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776 h1:tQIYjPdBoyREyB9XMu+nnTclpTYkz2zFM+lzLJFO4gQ=
153 | gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
154 |
--------------------------------------------------------------------------------
/siemcraft_addon_behavior/entities/panda.json:
--------------------------------------------------------------------------------
1 | {
2 | "format_version": "1.16.0",
3 | "minecraft:entity": {
4 | "description": {
5 | "identifier": "minecraft:panda",
6 | "is_spawnable": true,
7 | "is_summonable": true,
8 | "is_experimental": false
9 | },
10 | "component_groups": {
11 | "minecraft:panda_baby": {
12 | "minecraft:is_baby": {
13 | },
14 | "minecraft:scale": {
15 | "value": 0.4
16 | },
17 | "minecraft:ageable": {
18 | "duration": 1200,
19 | "feed_items": "bamboo",
20 | "grow_up": {
21 | "event": "minecraft:ageable_grow_up",
22 | "target": "self"
23 | }
24 | },
25 | "minecraft:behavior.roll": {
26 | "priority": 12,
27 | "probability": 0.0016
28 | },
29 | "minecraft:behavior.follow_parent": {
30 | "priority": 13,
31 | "speed_multiplier": 1.1
32 | },
33 | "minecraft:on_target_acquired": {
34 | "event": "minecraft:on_scared",
35 | "target": "self"
36 | },
37 | "minecraft:behavior.sneeze": {
38 | "priority": 7,
39 | "probability": 0.0001666,
40 | "cooldown_time": 1.0,
41 | "within_radius": 10.0,
42 | "entity_types": [
43 | {
44 | "filters": {
45 | "all_of": [
46 | {
47 | "test": "has_component",
48 | "subject": "other",
49 | "operator": "!=",
50 | "value": "minecraft:is_baby"
51 | },
52 | {
53 | "test": "is_family",
54 | "subject": "other",
55 | "value": "panda"
56 | },
57 | {
58 | "test": "in_water",
59 | "subject": "other",
60 | "operator": "!=",
61 | "value": true
62 | },
63 | {
64 | "test": "on_ground",
65 | "operator": "==",
66 | "value": true
67 | }
68 | ]
69 | },
70 | "max_dist": 10
71 | }
72 | ],
73 | "drop_item_chance": 0.001,
74 | "loot_table": "loot_tables/entities/panda_sneeze.json",
75 | "prepare_sound": "presneeze",
76 | "prepare_time": 1.0,
77 | "sound": "sneeze"
78 | }
79 | },
80 | "minecraft:panda_adult": {
81 | "minecraft:experience_reward": {
82 | "on_bred": "Math.Random(1,7)",
83 | "on_death": "query.last_hit_by_player ? Math.Random(1,3) : 0"
84 | },
85 | "minecraft:loot": {
86 | "table": "loot_tables/entities/panda.json"
87 | },
88 | "minecraft:behavior.breed": {
89 | "priority": 3,
90 | "speed_multiplier": 1.0
91 | },
92 | "minecraft:breedable": {
93 | "require_tame": false,
94 | "blend_attributes": false,
95 | "environment_requirements": {
96 | "blocks": "bamboo",
97 | "count": 8,
98 | "radius": 5
99 | },
100 | "breed_items": "bamboo",
101 | "breeds_with": {
102 | "mate_type": "minecraft:panda",
103 | "baby_type": "minecraft:panda",
104 | "breed_event": {
105 | "event": "minecraft:entity_born",
106 | "target": "baby"
107 | }
108 | },
109 | "mutation_factor": {
110 | "variant": 1.0
111 | }
112 | },
113 | "minecraft:on_target_acquired": {
114 | "event": "minecraft:become_angry",
115 | "target": "self"
116 | },
117 | "minecraft:on_target_escape": {
118 | "event": "minecraft:on_calm",
119 | "target": "self"
120 | },
121 | "minecraft:attack": {
122 | "damage": 2.0
123 | },
124 | "minecraft:behavior.melee_attack": {
125 | "priority": 2,
126 | "track_target": true,
127 | "reach_multiplier": 1.0
128 | },
129 | "minecraft:behavior.leap_at_target": {
130 | "priority": 4,
131 | "yd": 0.4,
132 | "must_be_on_ground": false
133 | },
134 | "minecraft:angry": {
135 | "duration": 10,
136 | "duration_delta": 3,
137 | "calm_event": {
138 | "event": "minecraft:become_calm",
139 | "target": "self"
140 | }
141 | },
142 | "minecraft:behavior.nearest_attackable_target": {
143 | "priority": 2,
144 | "must_see": true,
145 | "attack_interval": 5,
146 | "entity_types": [
147 | {
148 | "filters": {
149 | "any_of": [
150 | {
151 | "test": "is_family",
152 | "subject": "other",
153 | "value": "player"
154 | }
155 | ]
156 | },
157 | "max_dist": 16
158 | }
159 | ]
160 | }
161 | },
162 | "minecraft:panda_lazy": {
163 | "minecraft:variant": {
164 | "value": 1
165 | },
166 | "minecraft:behavior.lay_down": {
167 | "priority": 5,
168 | "interval": 400,
169 | "random_stop_interval": 2000
170 | },
171 | "minecraft:behavior.random_sitting": {
172 | "priority": 6,
173 | "start_chance": 0.02,
174 | "stop_chance": 0.2,
175 | "cooldown": 25,
176 | "min_sit_time": 15
177 | },
178 | "minecraft:behavior.snacking": {
179 | "priority": 3,
180 | "snacking_cooldown": 17.5,
181 | "snacking_cooldown_min": 10,
182 | "snacking_stop_chance": 0.0011,
183 | "items": [
184 | "bamboo",
185 | "cake"
186 | ]
187 | },
188 | "minecraft:behavior.panic": {
189 | "priority": 1,
190 | // Lazy panda's move half the speed, so double their multiplier when they panic
191 | // Otherwise, they don't actually look like they're panicking
192 | "speed_multiplier": 2.5
193 | },
194 | "minecraft:movement": {
195 | "value": 0.07
196 | }
197 | },
198 | "minecraft:panda_worried": {
199 | "minecraft:variant": {
200 | "value": 2
201 | },
202 | "minecraft:behavior.scared": {
203 | "priority": 1,
204 | "sound_interval": 20
205 | },
206 | "minecraft:behavior.avoid_mob_type": {
207 | "priority": 5,
208 | "max_dist": 16,
209 | "max_flee": 20,
210 | "entity_types": [
211 | {
212 | "filters": {
213 | "test": "is_family",
214 | "operator": "!=",
215 | "subject": "other",
216 | "value": "panda"
217 | },
218 | "max_dist": 16,
219 | "sprint_speed_multiplier": 1.5
220 | }
221 | ]
222 | }
223 | },
224 | "minecraft:panda_playful": {
225 | "minecraft:variant": {
226 | "value": 3
227 | },
228 | "minecraft:behavior.roll": {
229 | "priority": 12,
230 | "probability": 0.013
231 | }
232 | },
233 | "minecraft:panda_brown": {
234 | "minecraft:variant": {
235 | "value": 4
236 | }
237 | },
238 | "minecraft:panda_weak": {
239 | "minecraft:variant": {
240 | "value": 5
241 | },
242 | "minecraft:health": {
243 | "value": 10,
244 | "max": 10
245 | }
246 | },
247 | "minecraft:panda_sneezing": {
248 | "minecraft:behavior.sneeze": {
249 | "priority": 7,
250 | "probability": 0.002,
251 | "cooldown_time": 1.0,
252 | "within_radius": 10.0,
253 | "entity_types": [
254 | {
255 | "filters": {
256 | "all_of": [
257 | {
258 | "test": "has_component",
259 | "subject": "other",
260 | "operator": "!=",
261 | "value": "minecraft:is_baby"
262 | },
263 | {
264 | "test": "is_family",
265 | "subject": "other",
266 | "value": "panda"
267 | },
268 | {
269 | "test": "in_water",
270 | "subject": "other",
271 | "operator": "!=",
272 | "value": true
273 | },
274 | {
275 | "test": "on_ground",
276 | "operator": "==",
277 | "value": true
278 | }
279 | ]
280 | },
281 | "max_dist": 10
282 | }
283 | ],
284 | "drop_item_chance": 0.001,
285 | "loot_table": "loot_tables/entities/panda_sneeze.json",
286 | "prepare_sound": "presneeze",
287 | "prepare_time": 1.0,
288 | "sound": "sneeze"
289 | }
290 | },
291 | "minecraft:panda_aggressive": {
292 | "minecraft:type_family": {
293 | "family": [ "panda" , "panda_aggressive", "mob" ]
294 | },
295 | "minecraft:variant": {
296 | "value": 6
297 | },
298 | "minecraft:attack": {
299 | "damage": 6.0
300 | },
301 | "minecraft:behavior.melee_attack": {
302 | "priority": 2,
303 | "track_target": true,
304 | "reach_multiplier": 1.0
305 | },
306 | "minecraft:on_friendly_anger": {
307 | "event": "minecraft:on_anger",
308 | "target": "self"
309 | },
310 | "minecraft:behavior.panic": {
311 | "priority": 1,
312 | "speed_multiplier": 1.25,
313 | // Aggressive pandas don't panic from mob damage
314 | "ignore_mob_damage": true
315 | }
316 | },
317 | "minecraft:panda_angry": {
318 | "minecraft:angry": {
319 | "duration": 500,
320 | "broadcast_anger": true,
321 | "broadcast_range": 41,
322 | "broadcast_filters": {
323 | "test": "is_family",
324 | "operator": "==",
325 | "value": "panda_aggressive"
326 | },
327 | "calm_event": {
328 | "event": "minecraft:on_calm",
329 | "target": "self"
330 | }
331 | },
332 | "minecraft:on_target_acquired": {
333 | }
334 | },
335 | "minecraft:baby_scared": {
336 | "minecraft:angry": {
337 | "duration": 1,
338 | "broadcast_anger": true,
339 | "broadcast_range": 41,
340 | "broadcast_filters": {
341 | "test": "is_family",
342 | "operator": "==",
343 | "value": "panda_aggressive"
344 | },
345 | "calm_event": {
346 | "event": "minecraft:baby_on_calm",
347 | "target": "self"
348 | }
349 | }
350 | }
351 | },
352 |
353 |
354 | "components": {
355 | "minecraft:damage_sensor": {
356 | "triggers": [
357 | {
358 | "on_damage": {
359 | "filters": {
360 | "all_of": [
361 | { "test": "has_damage", "value": "fatal" },
362 | { "test": "is_family", "subject": "other", "value": "player" },
363 | { "none_of": { "test": "has_equipment", "domain": "hand", "subject": "other", "value": "diamond_sword"} }
364 | ]
365 | },
366 | "event": "special_death_event",
367 | "target": "self"
368 | }
369 | },
370 | {
371 | "on_damage": {
372 | "filters": {
373 | "all_of": [
374 | { "test": "has_damage", "value": "fatal" },
375 | { "test": "is_family", "subject": "other", "value": "player" },
376 | { "test": "has_equipment", "domain": "hand", "subject": "other", "value": "diamond_sword"}
377 | ]
378 | },
379 | "event": "special_death_event_diamond",
380 | "target": "self"
381 | }
382 | }
383 | ]
384 | },
385 | "minecraft:is_hidden_when_invisible": {
386 | },
387 | "minecraft:type_family": {
388 | "family": [ "panda" ]
389 | },
390 | "minecraft:breathable": {
391 | "total_supply": 15,
392 | "suffocate_time": 0
393 | },
394 | "minecraft:navigation.walk": {
395 | "can_float": true,
396 | "avoid_water": true,
397 | "avoid_damage_blocks": true
398 | },
399 | "minecraft:movement.basic": {
400 | },
401 | "minecraft:scale": {
402 | "value": 1.0
403 | },
404 | "minecraft:behavior.hurt_by_target": {
405 | "priority": 1
406 | },
407 | "minecraft:giveable": {
408 | "triggers": {
409 | "cooldown": 3.0,
410 | "items": [
411 | "bamboo",
412 | "cake"
413 | ],
414 | "on_give": {
415 | "event": "minecraft:on_calm",
416 | "target": "self"
417 | }
418 | }
419 | },
420 | "minecraft:inventory": {
421 | "inventory_size": 1,
422 | "private": true
423 | },
424 | "minecraft:jump.static": {
425 | },
426 | "minecraft:can_climb": {
427 | },
428 | "minecraft:collision_box": {
429 | "width": 1.7,
430 | "height": 1.5
431 | },
432 | "minecraft:nameable": {
433 | "alwaysShow": true
434 | },
435 | "minecraft:health": {
436 | "value": 20,
437 | "max": 20
438 | },
439 | "minecraft:hurt_on_condition": {
440 | "damage_conditions": [
441 | {
442 | "filters": { "test": "in_lava", "subject": "self", "operator": "==", "value": true },
443 | "cause": "lava",
444 | "damage_per_tick": 4
445 | }
446 | ]
447 | },
448 | "minecraft:movement": {
449 | "value": 0.15
450 | },
451 | "minecraft:water_movement": {
452 | "drag_factor": 0.98
453 | },
454 | "minecraft:despawn": {
455 | "despawn_from_distance": {}
456 | },
457 | "minecraft:behavior.float": {
458 | "priority": 0
459 | },
460 | "minecraft:behavior.random_sitting": {
461 | "priority": 5,
462 | "start_chance": 0.01,
463 | "stop_chance": 0.3,
464 | "cooldown": 30,
465 | "min_sit_time": 10
466 | },
467 | "minecraft:behavior.snacking": {
468 | "priority": 2,
469 | "snacking_cooldown": 22.5,
470 | "snacking_cooldown_min": 20,
471 | "snacking_stop_chance": 0.001334,
472 | "items": [
473 | "bamboo",
474 | "cake"
475 | ]
476 | },
477 | "minecraft:behavior.mount_pathing": {
478 | "priority": 5,
479 | "speed_multiplier": 1.5,
480 | "target_dist": 0.0,
481 | "track_target": true
482 | },
483 | "minecraft:behavior.breed": {
484 | "priority": 3,
485 | "speed_multiplier": 1.0
486 | },
487 | "minecraft:behavior.tempt": {
488 | "priority": 4,
489 | "speed_multiplier": 1.25,
490 | "items": [
491 | "bamboo"
492 | ]
493 | },
494 | "minecraft:behavior.random_stroll": {
495 | "priority": 14,
496 | "speed_multiplier": 0.8
497 | },
498 | "minecraft:behavior.look_at_player": {
499 | "priority": 8,
500 | "look_distance": 6.0,
501 | "probability": 0.02
502 | },
503 | "minecraft:behavior.random_look_around": {
504 | "priority": 9
505 | },
506 | "minecraft:behavior.panic": {
507 | "priority": 1,
508 | "speed_multiplier": 1.25
509 | },
510 | "minecraft:balloonable": {
511 | "mass": 1.5
512 | },
513 | "minecraft:rideable": {
514 | "seat_count": 1,
515 | "family_types": [
516 | "zombie"
517 | ],
518 | "seats": {
519 | "position": [ 0.0, 1.105, 0.0 ]
520 | }
521 | },
522 | "minecraft:physics": {
523 | },
524 | "minecraft:pushable": {
525 | "is_pushable": true,
526 | "is_pushable_by_piston": true
527 | },
528 | "minecraft:variant": {
529 | "value": 0
530 | },
531 | "minecraft:conditional_bandwidth_optimization": {
532 | },
533 | "minecraft:genetics": {
534 | "mutation_rate": 0.03125,
535 | "genes": [
536 | {
537 | "name": "panda_variant",
538 | "allele_range": {
539 | "range_min": 0,
540 | "range_max": 15
541 | },
542 | "genetic_variants": [
543 | {
544 | "main_allele": 0,
545 | "birth_event": {
546 | "event": "minecraft:panda_lazy",
547 | "target": "self"
548 | }
549 | },
550 | {
551 | "main_allele": 1,
552 | "birth_event": {
553 | "event": "minecraft:panda_worried",
554 | "target": "self"
555 | }
556 | },
557 | {
558 | "main_allele": 2,
559 | "birth_event": {
560 | "event": "minecraft:panda_playful",
561 | "target": "self"
562 | }
563 | },
564 | {
565 | "main_allele": 3,
566 | "birth_event": {
567 | "event": "minecraft:panda_aggressive",
568 | "target": "self"
569 | }
570 | },
571 | {
572 | "both_allele": {
573 | "range_min": 4,
574 | "range_max": 7
575 | },
576 | "birth_event": {
577 | "event": "minecraft:panda_weak",
578 | "target": "self"
579 | }
580 | },
581 | {
582 | "both_allele": {
583 | "range_min": 8,
584 | "range_max": 9
585 | },
586 | "birth_event": {
587 | "event": "minecraft:panda_brown",
588 | "target": "self"
589 | }
590 | }
591 | ]
592 | }
593 | ]
594 | }
595 | },
596 |
597 | "events": {
598 | "special_death_event": { },
599 | "special_death_event_diamond": { },
600 | "minecraft:entity_spawned": {
601 | "randomize": [
602 | {
603 | "weight": 95,
604 | "add": {
605 | "component_groups": [
606 | "minecraft:panda_adult"
607 | ]
608 | }
609 | },
610 | {
611 | "weight": 5,
612 | "add": {
613 | "component_groups": [
614 | "minecraft:panda_baby"
615 | ]
616 | }
617 | }
618 | ]
619 | },
620 |
621 | "minecraft:entity_born": {
622 | "add": {
623 | "component_groups": [
624 | "minecraft:panda_baby"
625 | ]
626 | }
627 | },
628 |
629 | "minecraft:ageable_grow_up": {
630 | "sequence": [
631 | {
632 | "remove": {
633 | "component_groups": [
634 | "minecraft:panda_baby"
635 | ]
636 | }
637 | },
638 | {
639 | "add": {
640 | "component_groups": [
641 | "minecraft:panda_adult"
642 | ]
643 | }
644 | },
645 | {
646 | "filters": {
647 | "test": "is_variant",
648 | "subject": "self",
649 | "operator": "==",
650 | "value": 3
651 | },
652 | "add": {
653 | "component_groups": [
654 | "minecraft:panda_playful"
655 | ]
656 | }
657 | },
658 | {
659 | "filters": {
660 | "test": "is_variant",
661 | "subject": "self",
662 | "operator": "==",
663 | "value": 6
664 | },
665 | "add": {
666 | "component_groups": [
667 | "minecraft:panda_aggressive"
668 | ]
669 | }
670 | }
671 | ]
672 | },
673 | "minecraft:panda_lazy": {
674 | "add": {
675 | "component_groups": [
676 | "minecraft:panda_lazy"
677 | ]
678 | }
679 | },
680 | "minecraft:panda_worried": {
681 | "add": {
682 | "component_groups": [
683 | "minecraft:panda_worried"
684 | ]
685 | }
686 | },
687 | "minecraft:panda_playful": {
688 | "add": {
689 | "component_groups": [
690 | "minecraft:panda_playful"
691 | ]
692 | }
693 | },
694 | "minecraft:panda_brown": {
695 | "add": {
696 | "component_groups": [
697 | "minecraft:panda_brown"
698 | ]
699 | }
700 | },
701 | "minecraft:panda_weak": {
702 | "sequence": [
703 | {
704 | "add": {
705 | "component_groups": [
706 | "minecraft:panda_weak"
707 | ]
708 | }
709 | },
710 | {
711 | "filters": {
712 | "test": "has_component",
713 | "operator": "==",
714 | "value": "minecraft:is_baby"
715 | },
716 | "add": {
717 | "component_groups": [
718 | "minecraft:panda_sneezing"
719 | ]
720 | }
721 | }
722 | ]
723 | },
724 | "minecraft:panda_aggressive": {
725 | "add": {
726 | "component_groups": [
727 | "minecraft:panda_aggressive"
728 | ]
729 | }
730 | },
731 | "minecraft:on_scared": {
732 | "add": {
733 | "component_groups": [
734 | "minecraft:baby_scared"
735 | ]
736 | }
737 | },
738 | "minecraft:baby_on_calm": {
739 | "remove": {
740 | "component_groups": [
741 | "minecraft:baby_scared"
742 | ]
743 | }
744 | },
745 | "minecraft:become_angry": {
746 | "add": {
747 | "component_groups": [
748 | "minecraft:panda_angry"
749 | ]
750 | }
751 | },
752 | "minecraft:on_calm": {
753 | }
754 | }
755 | }
756 | }
--------------------------------------------------------------------------------