diff --git a/RawAssets/fire_extinguisher.bbmodel b/RawAssets/fire_extinguisher.bbmodel index 272d13a..5b6a3b1 100644 --- a/RawAssets/fire_extinguisher.bbmodel +++ b/RawAssets/fire_extinguisher.bbmodel @@ -1 +1 @@ -{"meta":{"format_version":"4.0","creation_time":1651587755,"model_format":"java_block","box_uv":false},"name":"fire_extinguisher","parent":"fire_hydrant","ambientocclusion":true,"front_gui_light":false,"visible_box":[1,1,0],"variable_placeholders":"","variable_placeholder_buttons":[],"resolution":{"width":32,"height":32},"elements":[{"name":"cube","rescale":false,"locked":false,"from":[6,0,6.125],"to":[10,10.5,10.125],"autouv":0,"color":5,"origin":[8,0,7.125],"faces":{"north":{"uv":[0,0,4,11],"texture":0},"east":{"uv":[4,0,8,11],"texture":0},"south":{"uv":[8,0,12,11],"texture":0},"west":{"uv":[0,11,4,22],"texture":0},"up":{"uv":[23,14,19,10],"texture":0},"down":{"uv":[23,14,19,18],"texture":0}},"type":"cube","uuid":"86ed7822-e545-c1bd-cb07-412403277e3b"},{"name":"cube","rescale":false,"locked":false,"from":[9.5,0,6.625],"to":[10.5,10,9.625],"autouv":0,"color":2,"origin":[8,0,7.125],"faces":{"north":{"uv":[19,18,20,28],"texture":0},"east":{"uv":[4,11,7,21],"texture":0},"south":{"uv":[13,20,14,30],"texture":0},"west":{"uv":[7,11,10,21],"texture":0},"up":{"uv":[22,9,21,6],"texture":0},"down":{"uv":[9,21,8,24],"texture":0}},"type":"cube","uuid":"0788815b-53eb-823a-d654-275d4bfb5e55"},{"name":"cube","rescale":false,"locked":false,"from":[6.5,0,9.625],"to":[9.5,10,10.625],"autouv":0,"color":2,"origin":[8,0,7.125],"faces":{"north":{"uv":[10,11,13,21],"texture":0},"east":{"uv":[14,20,15,30],"texture":0},"south":{"uv":[12,0,15,10],"texture":0},"west":{"uv":[15,20,16,30],"texture":0},"up":{"uv":[12,22,9,21],"texture":0},"down":{"uv":[24,9,21,10],"texture":0}},"type":"cube","uuid":"7251e0f3-eeb2-876b-c7e9-1a2206f457aa"},{"name":"cube","rescale":false,"locked":false,"from":[6.5,0,5.625],"to":[9.5,10,6.625],"autouv":0,"color":2,"origin":[8,0,7.125],"faces":{"north":{"uv":[13,10,16,20],"texture":0},"east":{"uv":[16,20,17,30],"texture":0},"south":{"uv":[15,0,18,10],"texture":0},"west":{"uv":[17,20,18,30],"texture":0},"up":{"uv":[24,19,21,18],"texture":0},"down":{"uv":[24,19,21,20],"texture":0}},"type":"cube","uuid":"6fd103f1-f63f-cd3a-b336-ab2af0cc70c3"},{"name":"cube","rescale":false,"locked":false,"from":[5.5,0,6.625],"to":[6.5,10,9.625],"autouv":0,"color":2,"origin":[8,0,7.125],"faces":{"north":{"uv":[18,20,19,30],"texture":0},"east":{"uv":[16,10,19,20],"texture":0},"south":{"uv":[20,18,21,28],"texture":0},"west":{"uv":[18,0,21,10],"texture":0},"up":{"uv":[13,24,12,21],"texture":0},"down":{"uv":[22,20,21,23],"texture":0}},"type":"cube","uuid":"f8fe3823-c7be-d513-698b-f301d9e7c9bf"},{"name":"cube","rescale":false,"locked":false,"from":[6.5,10,6.625],"to":[9.5,11,9.625],"autouv":0,"color":2,"origin":[8,0,7.125],"faces":{"north":{"uv":[0,22,3,23],"texture":0},"east":{"uv":[22,6,25,7],"texture":0},"south":{"uv":[22,7,25,8],"texture":0},"west":{"uv":[22,8,25,9],"texture":0},"up":{"uv":[24,3,21,0],"texture":0},"down":{"uv":[24,3,21,6],"texture":0}},"type":"cube","uuid":"c8a4dff9-a7c0-669f-bd8e-1a1cb3c3b7a8"},{"name":"cube","rescale":false,"locked":false,"from":[7.5,11,7.625],"to":[8.5,13,8.625],"autouv":0,"color":3,"origin":[8,0,7.125],"faces":{"north":{"uv":[10,23,11,25],"texture":0},"east":{"uv":[23,10,24,12],"texture":0},"south":{"uv":[11,23,12,25],"texture":0},"west":{"uv":[23,12,24,14],"texture":0},"up":{"uv":[13,11,12,10],"texture":0},"down":{"uv":[3,24,2,25],"texture":0}},"type":"cube","uuid":"e5ee6137-1632-0c93-c253-bd9d439796c0"},{"name":"cube","rescale":false,"locked":false,"from":[7.75,12,6.625],"to":[8.25,12.5,8.125],"autouv":0,"color":4,"origin":[8,0,7.125],"faces":{"north":{"uv":[4,24,5,25],"texture":0},"east":{"uv":[23,14,25,15],"texture":0},"south":{"uv":[24,4,25,5],"texture":0},"west":{"uv":[23,15,25,16],"texture":0},"up":{"uv":[24,18,23,16],"texture":0},"down":{"uv":[22,23,21,25],"texture":0}},"type":"cube","uuid":"8de9797b-36f9-fe71-31a8-478b64c3d3b9"},{"name":"cube","rescale":false,"locked":false,"from":[7.5,11.75,5.625],"to":[8.5,12.75,7.125],"autouv":0,"color":5,"origin":[8,0,7.125],"faces":{"north":{"uv":[5,24,6,25],"texture":0},"east":{"uv":[23,21,25,22],"texture":0},"south":{"uv":[24,5,25,6],"texture":0},"west":{"uv":[23,22,25,23],"texture":0},"up":{"uv":[24,25,23,23],"texture":0},"down":{"uv":[1,24,0,26],"texture":0}},"type":"cube","uuid":"0aded044-0ed7-d730-72b6-a94bf6087ffb"},{"name":"cube","rescale":false,"locked":false,"from":[7.25,11.5,5.625],"to":[8.75,13,6.125],"autouv":0,"color":5,"origin":[8,0,7.125],"faces":{"north":{"uv":[4,21,6,23],"texture":0},"east":{"uv":[24,0,25,2],"texture":0},"south":{"uv":[6,21,8,23],"texture":0},"west":{"uv":[1,24,2,26],"texture":0},"up":{"uv":[26,3,24,2],"texture":0},"down":{"uv":[26,3,24,4],"texture":0}},"type":"cube","uuid":"81e1033e-817e-c6d2-4595-269d9b5b8b81"},{"name":"cube","rescale":false,"locked":false,"from":[7,12,7.875],"to":[7.5,12.5,8.375],"autouv":0,"color":5,"origin":[8,0,7.125],"faces":{"north":{"uv":[6,24,7,25],"texture":0},"east":{"uv":[8,24,9,25],"texture":0},"south":{"uv":[24,9,25,10],"texture":0},"west":{"uv":[24,10,25,11],"texture":0},"up":{"uv":[25,12,24,11],"texture":0},"down":{"uv":[13,24,12,25],"texture":0}},"type":"cube","uuid":"fc55e995-c28d-79f0-2bf1-f5d2abfe5cc3"},{"name":"cube","rescale":false,"locked":false,"from":[7,11.75,7.625],"to":[7.25,12.75,8.625],"autouv":0,"color":1,"origin":[8,0,7.125],"faces":{"north":{"uv":[24,12,25,13],"texture":0},"east":{"uv":[24,13,25,14],"texture":0},"south":{"uv":[24,16,25,17],"texture":0},"west":{"uv":[24,17,25,18],"texture":0},"up":{"uv":[25,19,24,18],"texture":0},"down":{"uv":[25,19,24,20],"texture":0}},"type":"cube","uuid":"f1ba7273-3ca2-4fef-b34c-fa608d1f4f23"},{"name":"cube","rescale":false,"locked":false,"from":[7.75,12.5,8.125],"to":[8.25,12.75,11.125],"autouv":0,"color":0,"origin":[8,0,7.125],"faces":{"north":{"uv":[22,24,23,25],"texture":0},"east":{"uv":[9,22,12,23],"texture":0},"south":{"uv":[24,23,25,24],"texture":0},"west":{"uv":[22,20,25,21],"texture":0},"up":{"uv":[4,25,3,22],"texture":0},"down":{"uv":[23,21,22,24],"texture":0}},"type":"cube","uuid":"abac36f3-a4fc-9b1b-68ec-1aed9cee13ba"},{"name":"cube","rescale":false,"locked":false,"from":[7.75,11.305849108714193,12.939915792601582],"to":[8.25,11.555849108714193,15.689915792601582],"autouv":0,"color":0,"rotation":[-22.5,0,0],"origin":[8,0,7.125],"faces":{"north":{"uv":[24,24,25,25],"texture":0},"east":{"uv":[0,23,3,24],"texture":0},"south":{"uv":[25,0,26,1],"texture":0},"west":{"uv":[4,23,7,24],"texture":0},"up":{"uv":[8,26,7,23],"texture":0},"down":{"uv":[10,23,9,26],"texture":0}},"type":"cube","uuid":"8779d0cf-db10-8fa5-69fd-f0a964c961c8"}],"outliner":["86ed7822-e545-c1bd-cb07-412403277e3b","0788815b-53eb-823a-d654-275d4bfb5e55","7251e0f3-eeb2-876b-c7e9-1a2206f457aa","6fd103f1-f63f-cd3a-b336-ab2af0cc70c3","f8fe3823-c7be-d513-698b-f301d9e7c9bf","c8a4dff9-a7c0-669f-bd8e-1a1cb3c3b7a8","e5ee6137-1632-0c93-c253-bd9d439796c0","8de9797b-36f9-fe71-31a8-478b64c3d3b9","0aded044-0ed7-d730-72b6-a94bf6087ffb","81e1033e-817e-c6d2-4595-269d9b5b8b81","fc55e995-c28d-79f0-2bf1-f5d2abfe5cc3","f1ba7273-3ca2-4fef-b34c-fa608d1f4f23","abac36f3-a4fc-9b1b-68ec-1aed9cee13ba","8779d0cf-db10-8fa5-69fd-f0a964c961c8"],"textures":[{"path":"D:\\FPE\\src\\main\\resources\\assets\\fire_protection_equipment\\textures\\item\\fire_extinguisher.png","name":"fire_extinguisher.png","folder":"item","namespace":"fire_protection_equipment","id":"0","particle":true,"render_mode":"default","visible":true,"mode":"bitmap","saved":true,"uuid":"3d7984f0-131d-a9fb-3ee7-2e325c330a66","relative_path":"../../src/main/resources/assets/fire_protection_equipment/textures/item/fire_extinguisher.png","source":"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAAAXNSR0IArs4c6QAAAHhJREFUWEftl0EKwCAMBJNf9on9pSWHXEpsSCkJhfEiqLDj6GX1WLKkYZwqGsVoB8Au3IBaACxo1MA4wPgTAIABDGAAAxjAAAYw8A8DEaV1Blv32YtF1iWebnwvJ2FbyYoSADsDFfVu+dMnaAPI/khl/5WBSkB29gIOkWMhyBFnDwAAAABJRU5ErkJggg=="}]} \ No newline at end of file +{"meta":{"format_version":"4.0","creation_time":1651984037,"model_format":"java_block","box_uv":false},"name":"fire_extinguisher","parent":"fire_hydrant","ambientocclusion":true,"front_gui_light":false,"visible_box":[1,1,0],"variable_placeholders":"","variable_placeholder_buttons":[],"resolution":{"width":32,"height":32},"elements":[{"name":"cube","rescale":false,"locked":false,"from":[6,0,6.125],"to":[10,10.5,10.125],"autouv":0,"color":5,"origin":[8,0,7.125],"faces":{"north":{"uv":[0,0,4,11],"texture":0},"east":{"uv":[4,0,8,11],"texture":0},"south":{"uv":[8,0,12,11],"texture":0},"west":{"uv":[0,11,4,22],"texture":0},"up":{"uv":[23,14,19,10],"texture":0},"down":{"uv":[23,14,19,18],"texture":0}},"type":"cube","uuid":"86ed7822-e545-c1bd-cb07-412403277e3b"},{"name":"cube","rescale":false,"locked":false,"from":[9.5,0,6.625],"to":[10.5,10,9.625],"autouv":0,"color":2,"origin":[8,0,7.125],"faces":{"north":{"uv":[19,18,20,28],"texture":0},"east":{"uv":[4,11,7,21],"texture":0},"south":{"uv":[13,20,14,30],"texture":0},"west":{"uv":[7,11,10,21],"texture":0},"up":{"uv":[22,9,21,6],"texture":0},"down":{"uv":[9,21,8,24],"texture":0}},"type":"cube","uuid":"0788815b-53eb-823a-d654-275d4bfb5e55"},{"name":"cube","rescale":false,"locked":false,"from":[6.5,0,9.625],"to":[9.5,10,10.625],"autouv":0,"color":2,"origin":[8,0,7.125],"faces":{"north":{"uv":[10,11,13,21],"texture":0},"east":{"uv":[14,20,15,30],"texture":0},"south":{"uv":[12,0,15,10],"texture":0},"west":{"uv":[15,20,16,30],"texture":0},"up":{"uv":[12,22,9,21],"texture":0},"down":{"uv":[24,9,21,10],"texture":0}},"type":"cube","uuid":"7251e0f3-eeb2-876b-c7e9-1a2206f457aa"},{"name":"cube","rescale":false,"locked":false,"from":[6.5,0,5.625],"to":[9.5,10,6.625],"autouv":0,"color":2,"origin":[8,0,7.125],"faces":{"north":{"uv":[13,10,16,20],"texture":0},"east":{"uv":[16,20,17,30],"texture":0},"south":{"uv":[15,0,18,10],"texture":0},"west":{"uv":[17,20,18,30],"texture":0},"up":{"uv":[24,19,21,18],"texture":0},"down":{"uv":[24,19,21,20],"texture":0}},"type":"cube","uuid":"6fd103f1-f63f-cd3a-b336-ab2af0cc70c3"},{"name":"cube","rescale":false,"locked":false,"from":[5.5,0,6.625],"to":[6.5,10,9.625],"autouv":0,"color":2,"origin":[8,0,7.125],"faces":{"north":{"uv":[18,20,19,30],"texture":0},"east":{"uv":[16,10,19,20],"texture":0},"south":{"uv":[20,18,21,28],"texture":0},"west":{"uv":[18,0,21,10],"texture":0},"up":{"uv":[13,24,12,21],"texture":0},"down":{"uv":[22,20,21,23],"texture":0}},"type":"cube","uuid":"f8fe3823-c7be-d513-698b-f301d9e7c9bf"},{"name":"cube","rescale":false,"locked":false,"from":[6.5,10,6.625],"to":[9.5,11,9.625],"autouv":0,"color":2,"origin":[8,0,7.125],"faces":{"north":{"uv":[0,22,3,23],"texture":0},"east":{"uv":[22,6,25,7],"texture":0},"south":{"uv":[22,7,25,8],"texture":0},"west":{"uv":[22,8,25,9],"texture":0},"up":{"uv":[24,3,21,0],"texture":0},"down":{"uv":[24,3,21,6],"texture":0}},"type":"cube","uuid":"c8a4dff9-a7c0-669f-bd8e-1a1cb3c3b7a8"},{"name":"cube","rescale":false,"locked":false,"from":[7.5,11,7.625],"to":[8.5,13,8.625],"autouv":0,"color":3,"origin":[8,0,7.125],"faces":{"north":{"uv":[10,23,11,25],"texture":0},"east":{"uv":[23,10,24,12],"texture":0},"south":{"uv":[11,23,12,25],"texture":0},"west":{"uv":[23,12,24,14],"texture":0},"up":{"uv":[13,11,12,10],"texture":0},"down":{"uv":[3,24,2,25],"texture":0}},"type":"cube","uuid":"e5ee6137-1632-0c93-c253-bd9d439796c0"},{"name":"cube","rescale":false,"locked":false,"from":[7.75,12,6.625],"to":[8.25,12.5,8.125],"autouv":0,"color":4,"origin":[8,0,7.125],"faces":{"north":{"uv":[4,24,5,25],"texture":0},"east":{"uv":[23,14,25,15],"texture":0},"south":{"uv":[24,4,25,5],"texture":0},"west":{"uv":[23,15,25,16],"texture":0},"up":{"uv":[24,18,23,16],"texture":0},"down":{"uv":[22,23,21,25],"texture":0}},"type":"cube","uuid":"8de9797b-36f9-fe71-31a8-478b64c3d3b9"},{"name":"cube","rescale":false,"locked":false,"from":[7.5,11.75,5.625],"to":[8.5,12.75,7.125],"autouv":0,"color":5,"origin":[8,0,7.125],"faces":{"north":{"uv":[5,24,6,25],"texture":0},"east":{"uv":[23,21,25,22],"texture":0},"south":{"uv":[24,5,25,6],"texture":0},"west":{"uv":[23,22,25,23],"texture":0},"up":{"uv":[24,25,23,23],"texture":0},"down":{"uv":[1,24,0,26],"texture":0}},"type":"cube","uuid":"0aded044-0ed7-d730-72b6-a94bf6087ffb"},{"name":"cube","rescale":false,"locked":false,"from":[7.25,11.5,5.625],"to":[8.75,13,6.125],"autouv":0,"color":5,"origin":[8,0,7.125],"faces":{"north":{"uv":[4,21,6,23],"texture":0},"east":{"uv":[24,0,25,2],"texture":0},"south":{"uv":[6,21,8,23],"texture":0},"west":{"uv":[1,24,2,26],"texture":0},"up":{"uv":[26,3,24,2],"texture":0},"down":{"uv":[26,3,24,4],"texture":0}},"type":"cube","uuid":"81e1033e-817e-c6d2-4595-269d9b5b8b81"},{"name":"cube","rescale":false,"locked":false,"from":[7,12,7.875],"to":[7.5,12.5,8.375],"autouv":0,"color":5,"origin":[8,0,7.125],"faces":{"north":{"uv":[6,24,7,25],"texture":0},"east":{"uv":[8,24,9,25],"texture":0},"south":{"uv":[24,9,25,10],"texture":0},"west":{"uv":[24,10,25,11],"texture":0},"up":{"uv":[25,12,24,11],"texture":0},"down":{"uv":[13,24,12,25],"texture":0}},"type":"cube","uuid":"fc55e995-c28d-79f0-2bf1-f5d2abfe5cc3"},{"name":"cube","rescale":false,"locked":false,"from":[7,11.75,7.625],"to":[7.25,12.75,8.625],"autouv":0,"color":1,"origin":[8,0,7.125],"faces":{"north":{"uv":[24,12,25,13],"texture":0},"east":{"uv":[24,13,25,14],"texture":0},"south":{"uv":[24,16,25,17],"texture":0},"west":{"uv":[24,17,25,18],"texture":0},"up":{"uv":[25,19,24,18],"texture":0},"down":{"uv":[25,19,24,20],"texture":0}},"type":"cube","uuid":"f1ba7273-3ca2-4fef-b34c-fa608d1f4f23"},{"name":"cube","rescale":false,"locked":false,"from":[7.75,12.5,8.125],"to":[8.25,12.75,11.125],"autouv":0,"color":0,"origin":[8,0,7.125],"faces":{"north":{"uv":[22,24,23,25],"texture":0},"east":{"uv":[9,22,12,23],"texture":0},"south":{"uv":[24,23,25,24],"texture":0},"west":{"uv":[22,20,25,21],"texture":0},"up":{"uv":[4,25,3,22],"texture":0},"down":{"uv":[23,21,22,24],"texture":0}},"type":"cube","uuid":"abac36f3-a4fc-9b1b-68ec-1aed9cee13ba"},{"name":"cube","rescale":false,"locked":false,"from":[7.75,11.305849108714193,12.939915792601582],"to":[8.25,11.555849108714193,15.689915792601582],"autouv":0,"color":0,"rotation":[-22.5,0,0],"origin":[8,0,7.125],"faces":{"north":{"uv":[24,24,25,25],"texture":0},"east":{"uv":[0,23,3,24],"texture":0},"south":{"uv":[25,0,26,1],"texture":0},"west":{"uv":[4,23,7,24],"texture":0},"up":{"uv":[8,26,7,23],"texture":0},"down":{"uv":[10,23,9,26],"texture":0}},"type":"cube","uuid":"8779d0cf-db10-8fa5-69fd-f0a964c961c8"}],"outliner":["86ed7822-e545-c1bd-cb07-412403277e3b","0788815b-53eb-823a-d654-275d4bfb5e55","7251e0f3-eeb2-876b-c7e9-1a2206f457aa","6fd103f1-f63f-cd3a-b336-ab2af0cc70c3","f8fe3823-c7be-d513-698b-f301d9e7c9bf","c8a4dff9-a7c0-669f-bd8e-1a1cb3c3b7a8","e5ee6137-1632-0c93-c253-bd9d439796c0","8de9797b-36f9-fe71-31a8-478b64c3d3b9","0aded044-0ed7-d730-72b6-a94bf6087ffb","81e1033e-817e-c6d2-4595-269d9b5b8b81","fc55e995-c28d-79f0-2bf1-f5d2abfe5cc3","f1ba7273-3ca2-4fef-b34c-fa608d1f4f23","abac36f3-a4fc-9b1b-68ec-1aed9cee13ba","8779d0cf-db10-8fa5-69fd-f0a964c961c8"],"textures":[{"path":"D:\\FPE\\src\\main\\resources\\assets\\fire_protection_equipment\\textures\\block\\fire_extinguisher.png","name":"fire_extinguisher.png","folder":"block","namespace":"fire_protection_equipment","id":"0","particle":true,"render_mode":"default","visible":true,"mode":"bitmap","saved":true,"uuid":"3d7984f0-131d-a9fb-3ee7-2e325c330a66","relative_path":"../../src/main/resources/assets/fire_protection_equipment/textures/block/fire_extinguisher.png","source":"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAAAXNSR0IArs4c6QAAAf5JREFUWEftls9OwkAQxqcWDcqh3kroxRMPwAVuJJw9SXwJHogH4GjEd+AGFx6AaGIiTeAGB5QoWPM1mXW6of9Jg4l7YVt2O7/9ZvbbNV6qVc80TUK7KJfpc7v1+9zku/1+Tzz22/PozDDUuPNKRfW/NhvVXwyH1Ov1aDqd/g4W3zeKAGi1WgeDgyMWACvjFWVVAIHCIIzVfO6tmk1flOvJhLjPz+/ttkrLnwTAQm5cN3sKjlGEuWogC8DHek2lUknVeuEK/ANII7qz7VATSuQDeg3c12r0uFgEXJCTLbcp5t1aFvX7/VAP8AHcet2T1ov8cZOFJMfoNhwFgP/CbFgBsGRwvSQAMCxu0rgOKXD6ANKK8yoQOEaJCCdh1DngpyALQFgNZAJAEaatgTQAUXeBzEV4sgC73Y4uLUvdH7DCWCM6ZgoKA0AgmJR0Sd5BrABWzi2VEb0NBoFirna7JHPOgZIAwIZjt+Gr4ygrBjVPYgoAyNU8LZckFbgajfyhm07Hd1GpQCKARqMROAv0vYyAYQB8b9QBoCK2HwBit+F4PPYBeKUICAeTzxIAYx9cV914+FyQCgAA8/k7kTciBjh0b4M6KCD+ZXWebdvTT0pZhM5sFnoJ1RVOPFBOPDkAbEfPNFURFq4AA6QJzIoeJQWFA+iFlOc5kwJ5AupzfwAfGCg/vNQbNwAAAABJRU5ErkJggg=="}],"display":{"thirdperson_righthand":{"translation":[0,-4.5,-0.5]},"thirdperson_lefthand":{"translation":[0,-4.5,-0.5]},"firstperson_righthand":{"translation":[-9,0,0]},"firstperson_lefthand":{"translation":[-9,0,0]},"ground":{"translation":[0,4,0]},"gui":{"rotation":[0,120,30],"translation":[0,1.5,0]},"head":{"translation":[0,14.25,0]}}} \ No newline at end of file diff --git a/build.gradle b/build.gradle index 0dd5e71..b730ca1 100644 --- a/build.gradle +++ b/build.gradle @@ -34,6 +34,8 @@ java.toolchain.languageVersion = JavaLanguageVersion.of(17) minecraft { mappings channel: "parchment", version: "2022.03.13-1.18.2" + accessTransformer = file('src/main/resources/META-INF/accesstransformer.cfg') + runs { client { workingDirectory project.file("run_client") @@ -64,6 +66,8 @@ sourceSets.main.resources { } repositories { + maven { url = "https://files.minecraftforge.net/maven" } + maven { url = "https://maven.parchmentmc.org" } maven { url "https://cursemaven.com"; content {includeGroup("curse.maven") } } } diff --git a/src/main/java/restricted/fpe/mixin/MixinFurnaceTileEntity.java b/src/main/java/restricted/fpe/mixin/MixinFurnaceTileEntity.java index 32b3aa4..d0bbd9e 100644 --- a/src/main/java/restricted/fpe/mixin/MixinFurnaceTileEntity.java +++ b/src/main/java/restricted/fpe/mixin/MixinFurnaceTileEntity.java @@ -27,8 +27,9 @@ public abstract class MixinFurnaceTileEntity { @Inject(method = "serverTick", at = @At("HEAD")) private static void serverTick(Level pLevel, BlockPos pPos, BlockState pState, AbstractFurnaceBlockEntity pBlockEntity, CallbackInfo ci) { + var mixinFurnaceEntity = (MixinFurnaceTileEntity) (Object) pBlockEntity; if(pBlockEntity instanceof FurnaceBlockEntity) { - var isLit = ((MixinFurnaceTileEntity)(Object) pBlockEntity).isLit(); + var isLit = mixinFurnaceEntity.isLit(); if(isLit) { if(RANDOM.nextInt(100) > 98) { var blockPosToFire = getAnyBlockPosCanFire(pLevel, pPos); diff --git a/src/main/kotlin/restricted/fpe/FPEConst.kt b/src/main/kotlin/restricted/fpe/FPEConst.kt new file mode 100644 index 0000000..0d87643 --- /dev/null +++ b/src/main/kotlin/restricted/fpe/FPEConst.kt @@ -0,0 +1,65 @@ +package restricted.fpe + +import net.minecraft.core.Direction +import net.minecraft.world.damagesource.DamageSource +import net.minecraft.world.item.* +import net.minecraft.world.item.enchantment.EnchantmentCategory +import net.minecraft.world.level.block.SoundType +import net.minecraft.world.level.block.state.BlockBehaviour +import net.minecraft.world.level.block.state.properties.EnumProperty +import net.minecraft.world.level.material.Material + +private typealias ItemProperties = Item.Properties +private typealias BlockProperties = BlockBehaviour.Properties + +object FPEConst { + + object BlockConst { + + // BlockBehavior.Properties + + val FireHydrantProp: BlockProperties = + BlockProperties.of(Material.HEAVY_METAL).strength(5.0F, 1200.0F).sound(SoundType.ANVIL).noOcclusion() + + val FireExtinguishingBombProp: BlockProperties = + BlockProperties.of(Material.EXPLOSIVE).instabreak().sound(SoundType.GRASS) + + val FireDetectorProp: BlockProperties = + BlockProperties.of(Material.WOOL).strength(0.8F).sound(SoundType.WOOL).noOcclusion().lightLevel { 3 } + + val FireSprinklerProp: BlockProperties = + BlockProperties.of(Material.WOOL).strength(0.8F).sound(SoundType.WOOL).noOcclusion().lightLevel { 3 } + + // Property for BlockState + + val VERTICAL_FACING: EnumProperty = + EnumProperty.create("facing", Direction::class.java, Direction.UP, Direction.DOWN) + + } + + object ItemConst { + + // Item.Properties + + val DefaultItemProp: ItemProperties = + Item.Properties().tab(FPE.Tabs.Default) + + val DefaultNonStackableItemProp: ItemProperties = + Item.Properties().stacksTo(1).tab(FPE.Tabs.Default) + + val FireExtinguisherProp: ItemProperties = + Item.Properties().rarity(Rarity.UNCOMMON).tab(FPE.Tabs.Default).stacksTo(1).durability(15000) + } + + object DamageSourceConst { + + val SpreadingFire = DamageSource("spreading_fire") + + val Extinguish = DamageSource("extinguish") + } + + object EnchantCategory { + val BowAndCrossbowCategory: EnchantmentCategory = EnchantmentCategory.create("bow_and_crossbow") { it is BowItem || it is CrossbowItem } + } + +} \ No newline at end of file diff --git a/src/main/kotlin/restricted/fpe/FPEKtExt.kt b/src/main/kotlin/restricted/fpe/FPEKtExt.kt index 3d93069..7a45ad8 100644 --- a/src/main/kotlin/restricted/fpe/FPEKtExt.kt +++ b/src/main/kotlin/restricted/fpe/FPEKtExt.kt @@ -15,17 +15,15 @@ import net.minecraft.world.level.material.Material import net.minecraft.world.phys.Vec3 import net.minecraftforge.registries.ForgeRegistryEntry import net.minecraftforge.registries.IForgeRegistryEntry +import restricted.fpe.FPEConst.ItemConst.DefaultItemProp -internal typealias MinecraftItems = net.minecraft.world.item.Items +internal typealias MinecraftItems = Items internal typealias MinecraftBlocks = net.minecraft.world.level.block.Blocks -internal val defaultItemProp = Item.Properties().tab(FPE.Tabs.Default) -internal val defaultSingleItemProp = Item.Properties().stacksTo(1).tab(FPE.Tabs.Default) - -internal fun Block.generateBlockItem(properties: Item.Properties = defaultItemProp): BlockItem = +internal fun Block.generateBlockItem(properties: Item.Properties = DefaultItemProp): BlockItem = BlockItem(this, properties) -internal fun buildItem(itemProp: Item.Properties = defaultItemProp): Item = Item(itemProp) +internal fun buildItem(itemProp: Item.Properties = DefaultItemProp): Item = Item(itemProp) internal fun buildItem(block: Item.Properties.() -> Unit): Item = buildItem(Item.Properties().apply(block)) internal val > ForgeRegistryEntry.registryPath get() = registryName?.path ?: error("") @@ -55,8 +53,7 @@ internal fun boundingBoxOfCenter(center: BlockPos, xOff: Int, yOff: Int = xOff, internal fun BoundingBox.forEach(block: (BlockPos) -> Unit) = BlockPos.betweenClosedStream(this).forEach(block) -internal fun Level.addParticle(particleOptions: ParticleOptions, loc: Vec3, speedX: Double, speedY: Double, speedZ: Double) = - addParticle(particleOptions, loc.x, loc.y, loc.z, speedX, speedY, speedZ) +internal val BoundingBox.AABB get() = net.minecraft.world.phys.AABB.of(this) internal fun buildSetBlockFlag( updateBlock: Boolean = false, @@ -94,4 +91,21 @@ internal fun Level.runOnRemote(block: ServerLevel.() -> R): R? { } else { null } -} \ No newline at end of file +} + +internal fun Level.letOnRemote(block: (ServerLevel) -> R): R? { + return if(this is ServerLevel) { + block(this) + } else { + null + } +} + +internal fun ServerLevel.sendParticles(particleOptions: ParticleOptions, pos: Vec3, count: Int, speed: Double, offset: Vec3 = Vec3.ZERO) = + sendParticles(particleOptions, pos.x, pos.y, pos.z, count, offset.x, offset.y, offset.z, speed) + +internal fun buildCompoundTag(block: CompoundTag.() -> Unit) = CompoundTag().apply(block) + +internal inline fun > enumValueOrNull(name: String) = enumValues().find { it.name == name } + +infix fun Int.ifZero(nonZeroValue: Int): Int = if(this == 0) { nonZeroValue } else { this } \ No newline at end of file diff --git a/src/main/kotlin/restricted/fpe/FireProtectEquipment.kt b/src/main/kotlin/restricted/fpe/FireProtectEquipment.kt index 88929f8..e343523 100644 --- a/src/main/kotlin/restricted/fpe/FireProtectEquipment.kt +++ b/src/main/kotlin/restricted/fpe/FireProtectEquipment.kt @@ -2,13 +2,12 @@ package restricted.fpe -import net.minecraft.core.particles.ParticleTypes -import net.minecraft.server.level.ServerLevel import net.minecraft.world.effect.MobEffect +import net.minecraft.world.entity.Entity import net.minecraft.world.item.* import net.minecraft.world.item.enchantment.Enchantment import net.minecraft.world.level.block.Block -import net.minecraft.world.level.block.Blocks +import net.minecraft.world.level.block.entity.BlockEntityType import net.minecraftforge.fml.common.Mod import net.minecraftforge.fml.event.lifecycle.FMLClientSetupEvent import net.minecraftforge.fml.event.lifecycle.FMLDedicatedServerSetupEvent @@ -16,17 +15,15 @@ import net.minecraftforge.registries.DeferredRegister import net.minecraftforge.registries.ForgeRegistries import org.apache.logging.log4j.LogManager import org.apache.logging.log4j.Logger -import restricted.fpe.block.FireHydrantBlock +import restricted.fpe.block.* +import restricted.fpe.block.entity.FireDetectorBlockEntity +import restricted.fpe.block.entity.FireSprinklerBlockEntity import restricted.fpe.enchant.FireWalkerEnchant import restricted.fpe.enchant.SpreadingFireEnchant -import restricted.fpe.extinguish.ExtinguishContext -import restricted.fpe.extinguish.ExtinguishRecipe -import restricted.fpe.extinguish.ExtinguishRecipe.MiniBlockState.Builder.Companion.buildMiniState -import restricted.fpe.item.FireExtinguisherItem -import restricted.fpe.item.FireItem +import restricted.fpe.extinguish.* +import restricted.fpe.item.* import restricted.fpe.potion.SpreadingFireEffect import thedarkcolour.kotlinforforge.forge.* -import kotlin.math.log const val ModId = "fire_protection_equipment" @@ -38,6 +35,7 @@ object FPE { init { Enchants.registry.register(MOD_BUS) MobEffects.registry.register(MOD_BUS) + BlockEntityTypes.registry.register(MOD_BUS) Blocks.registry.register(MOD_BUS) Items.registry.register(MOD_BUS) @@ -46,7 +44,7 @@ object FPE { serverTarget = { MOD_BUS.addListener(::serverSetup) } ) - registerFireRecipes() + BuiltInRecipes.register() } private fun clientSetup(e: FMLClientSetupEvent) { @@ -57,29 +55,13 @@ object FPE { private fun serverSetup(e: FMLDedicatedServerSetupEvent) { } - private fun registerFireRecipes() { - logger.info("Registering Fire Recipes") - - ExtinguishRecipe.register(MinecraftBlocks.FIRE.buildMiniState()) { ctx, _, pos -> - ctx.world.setBlock(pos, net.minecraft.world.level.block.Blocks.AIR.defaultBlockState(), buildSetBlockFlag(updateBlock = true, sendToClient = true)) - ctx.world.addParticle(ParticleTypes.SMOKE, pos.vec3, 0.0, 0.0, 0.0) - println("World = ${ctx.world is ServerLevel}") - ctx.world.runOnRemote { - val v3 = pos.vec3 - sendParticles(ParticleTypes.CLOUD, v3.x, v3.y, v3.z, (1..20).random(), 0.0, 0.0, 0.0, 0.2) - } - } - - logger.info("End register") - ExtinguishRecipe.recipes.cellSet().forEach { (state, type, func) -> - logger.info("$state & $type => $func") - }// TODO: Removal - } - object Blocks { internal val registry: DeferredRegister = DeferredRegister.create(ForgeRegistries.BLOCKS, ModId) val FireHydrant by registry.registerObject("fire_hydrant") { FireHydrantBlock } + val FireExtinguishingBomb by registry.registerObject("fire_extinguishing_bomb") { FireExtinguishingBombBlock } + val FireDetector by registry.registerObject("fire_detector") { FireDetectorBlock } + val FireSprinkler by registry.registerObject("fire_sprinkler") { FireSprinklerBlock } } object Items { @@ -90,8 +72,14 @@ object FPE { val FireHydrant by registry.registerObject("fire_hydrant") { Blocks.FireHydrant.generateBlockItem() } val BrokenFireHydrant by registry.registerObject("broken_fire_hydrant") { buildItem() } + val FireExtinguishingBomb by registry.registerObject("fire_extinguishing_bomb") { Blocks.FireExtinguishingBomb.generateBlockItem() } + val FireDetector by registry.registerObject("fire_detector") { Blocks.FireDetector.generateBlockItem() } + val FireSprinkler by registry.registerObject("fire_sprinkler") { Blocks.FireSprinkler.generateBlockItem() } val FireExtinguisher by registry.registerObject("fire_extinguisher") { FireExtinguisherItem } + + val FurnaceFireProtectionDevice by registry.registerObject("furnace_fire_protection_device") { FurnaceFireProtectionDeviceItem } + } object Tabs { @@ -115,13 +103,29 @@ object FPE { val SpreadingFire by registry.registerObject("spreading_fire") { SpreadingFireEffect } } + @Suppress("NULLABILITY_MISMATCH_BASED_ON_JAVA_ANNOTATIONS") + object BlockEntityTypes { + internal val registry: DeferredRegister> = DeferredRegister.create(ForgeRegistries.BLOCK_ENTITIES, ModId) + + val FireDetector: BlockEntityType by registry.registerObject("fire_detector") { BlockEntityType.Builder.of(::FireDetectorBlockEntity, Blocks.FireDetector).build(null) } + val FireSprinkler: BlockEntityType by registry.registerObject("fire_sprinkler") { BlockEntityType.Builder.of(::FireSprinklerBlockEntity, Blocks.FireSprinkler).build(null) } + } + fun extinguishFire(context: ExtinguishContext) { + val extinType = context.type context.boundingBox.forEach { - val state = context.world.getBlockState(it) - val func = ExtinguishRecipe[state, context.type] + val state = context.level.getBlockState(it) + val func = ExtinguishRecipe[state, extinType] if(func != null) { func(context, state, it) - println("$state & ${context.type.name} = $func") // TODO: Removal + logger.debug("Executed the ExtinguishRecipe for $state with type $extinType") + } + } + context.level.getEntitiesOfClass(Entity::class.java, context.boundingBox.AABB) { true }.forEach { + val func = ExtinguishRecipe.getForEntity(it.type, extinType) + if(func != null) { + func(context, it) + logger.debug("Executed the Entity ExtinguishRecipe for $it with type $extinType") } } } diff --git a/src/main/kotlin/restricted/fpe/block/FireDetectorBlock.kt b/src/main/kotlin/restricted/fpe/block/FireDetectorBlock.kt new file mode 100644 index 0000000..c3bddd7 --- /dev/null +++ b/src/main/kotlin/restricted/fpe/block/FireDetectorBlock.kt @@ -0,0 +1,96 @@ +package restricted.fpe.block + +import net.minecraft.core.BlockPos +import net.minecraft.core.Direction +import net.minecraft.tags.BlockTags +import net.minecraft.world.item.context.BlockPlaceContext +import net.minecraft.world.level.BlockGetter +import net.minecraft.world.level.Level +import net.minecraft.world.level.block.* +import net.minecraft.world.level.block.entity.* +import net.minecraft.world.level.block.state.BlockState +import net.minecraft.world.level.block.state.StateDefinition +import net.minecraft.world.phys.shapes.CollisionContext +import net.minecraft.world.phys.shapes.VoxelShape +import restricted.fpe.* +import restricted.fpe.FPEConst.BlockConst.VERTICAL_FACING +import restricted.fpe.block.entity.FireDetectorBlockEntity + +@Suppress("OVERRIDE_DEPRECATION") +object FireDetectorBlock : BaseEntityBlock(FPEConst.BlockConst.FireDetectorProp) { + + private val bottomShape = box(5.0, 0.0, 5.0, 11.0, 2.0, 11.0) + private val topShape = box(5.0, 14.0, 5.0, 11.0, 16.0, 11.0) + + init { + registerDefaultState( + this.stateDefinition.any().setValue(VERTICAL_FACING, Direction.UP) + ) + } + + fun hasFireAround(level: Level, blockPos: BlockPos): Boolean { + return level.getBlockStates(boundingBoxOfCenter(blockPos.below(2), 3).AABB).anyMatch { + it.`is`(BlockTags.FIRE) + } + } + + override fun createBlockStateDefinition(pBuilder: StateDefinition.Builder) { + pBuilder.add(VERTICAL_FACING) + } + + @Suppress("UNUSED_PARAMETER") + fun onTick(level: Level, pos: BlockPos, state: BlockState, blockEntity: FireDetectorBlockEntity) { + val hasFire = hasFireAround(level, pos) + if(hasFire != blockEntity.fireDetected) { + blockEntity.fireDetected = hasFire + level.updateNeighborsAt(pos, this) + } + } + + override fun getRenderShape(pState: BlockState): RenderShape { + return RenderShape.MODEL + } + + override fun getStateForPlacement(pContext: BlockPlaceContext): BlockState? { + val direction = if(pContext.clickedFace == Direction.UP) Direction.UP else Direction.DOWN + return defaultBlockState().setValue(VERTICAL_FACING, direction) + } + + override fun getShape( + pState: BlockState, + pLevel: BlockGetter, + pPos: BlockPos, + pContext: CollisionContext + ): VoxelShape { + return if(pState.getValue(VERTICAL_FACING) == Direction.UP) { + bottomShape + } else { + topShape + } + } + + override fun isSignalSource(state: BlockState): Boolean { + return true + } + + override fun getSignal(state: BlockState, level: BlockGetter, pos: BlockPos, pDirection: Direction): Int { + val blockEntity = level.getBlockEntity(pos, FPE.BlockEntityTypes.FireDetector) + return if(blockEntity.isPresent && blockEntity.get().fireDetected) { + 15 + } else { + 0 + } + } + + override fun newBlockEntity(pPos: BlockPos, pState: BlockState): BlockEntity { + return FireDetectorBlockEntity(pPos, pState) + } + + override fun getTicker( + pLevel: Level, + pState: BlockState, + pBlockEntityType: BlockEntityType + ): BlockEntityTicker? { + return createTickerHelper(pBlockEntityType, FPE.BlockEntityTypes.FireDetector, ::onTick) + } +} \ No newline at end of file diff --git a/src/main/kotlin/restricted/fpe/block/FireExtinguishingBombBlock.kt b/src/main/kotlin/restricted/fpe/block/FireExtinguishingBombBlock.kt new file mode 100644 index 0000000..a252d25 --- /dev/null +++ b/src/main/kotlin/restricted/fpe/block/FireExtinguishingBombBlock.kt @@ -0,0 +1,94 @@ +package restricted.fpe.block + +import net.minecraft.core.BlockPos +import net.minecraft.core.Direction +import net.minecraft.core.particles.ParticleTypes +import net.minecraft.world.InteractionHand +import net.minecraft.world.InteractionResult +import net.minecraft.world.entity.LivingEntity +import net.minecraft.world.entity.player.Player +import net.minecraft.world.item.Items +import net.minecraft.world.level.* +import net.minecraft.world.level.block.Block +import net.minecraft.world.level.block.state.BlockState +import net.minecraft.world.phys.BlockHitResult +import restricted.fpe.* +import restricted.fpe.extinguish.ExtinguishContext +import restricted.fpe.extinguish.ExtinguishContext.Companion.process +import restricted.fpe.extinguish.ExtinguishType +import restricted.fpe.runOnRemote + +@Suppress("OVERRIDE_DEPRECATION") +object FireExtinguishingBombBlock : Block(FPEConst.BlockConst.FireExtinguishingBombProp) { + + fun onExtinguish( + level: Level, + pos: BlockPos, + ignitePlayer: Player? = null + ) { + level.removeBlock(pos, false) + ExtinguishContext(level, pos, 8, ExtinguishType.DRY_ICE, player = ignitePlayer).process() + level.runOnRemote { + sendParticles(ParticleTypes.EXPLOSION, pos.vec3, 10, 0.2) + } + } + + // 300 = 被火焰燃烧时立刻烧毁(触发 #onCaughtFire) + override fun getFlammability(state: BlockState?, level: BlockGetter?, pos: BlockPos?, direction: Direction?): Int = + 300 + + // 被火焰烧毁时 + override fun onCaughtFire( + state: BlockState, + level: Level, + pos: BlockPos, + direction: Direction?, + igniter: LivingEntity? + ) { + onExtinguish(level, pos, igniter as? Player) + } + + // 被炸毁时 + override fun onBlockExploded(state: BlockState, level: Level, pos: BlockPos, explosion: Explosion) { + onExtinguish(level, pos, explosion.sourceMob as? Player) + } + + // 被打火石使用时 + override fun use( + state: BlockState, + world: Level, + pos: BlockPos, + player: Player, + hand: InteractionHand, + hit: BlockHitResult + ): InteractionResult { + val itemstack = player.getItemInHand(hand) + if(itemstack.item == Items.FLINT_AND_STEEL) { + onExtinguish(world, pos, player) + return InteractionResult.sidedSuccess(world.isClientSide) + } + return InteractionResult.PASS + } + + // 不能因爆炸掉落 + override fun canDropFromExplosion( + state: BlockState?, + level: BlockGetter?, + pos: BlockPos?, + explosion: Explosion? + ): Boolean = false + + // 当被红石触发时 + override fun neighborChanged( + state: BlockState, + level: Level, + pos: BlockPos, + block: Block, + fromPos: BlockPos, + isMoving: Boolean + ) { + if(level.hasNeighborSignal(pos)) { + onExtinguish(level, pos) + } + } +} \ No newline at end of file diff --git a/src/main/kotlin/restricted/fpe/block/FireHydrantBlock.kt b/src/main/kotlin/restricted/fpe/block/FireHydrantBlock.kt index 2b6c202..d429d5c 100644 --- a/src/main/kotlin/restricted/fpe/block/FireHydrantBlock.kt +++ b/src/main/kotlin/restricted/fpe/block/FireHydrantBlock.kt @@ -9,19 +9,18 @@ import net.minecraft.world.item.context.BlockPlaceContext import net.minecraft.world.item.enchantment.EnchantmentHelper import net.minecraft.world.item.enchantment.Enchantments import net.minecraft.world.level.BlockGetter -import net.minecraft.world.level.block.* -import net.minecraft.world.level.block.state.* -import net.minecraft.world.level.material.Material +import net.minecraft.world.level.block.Block +import net.minecraft.world.level.block.HorizontalDirectionalBlock +import net.minecraft.world.level.block.state.BlockState +import net.minecraft.world.level.block.state.StateDefinition import net.minecraft.world.level.storage.loot.LootContext import net.minecraft.world.level.storage.loot.parameters.LootContextParams import net.minecraft.world.phys.shapes.CollisionContext import net.minecraft.world.phys.shapes.VoxelShape import restricted.fpe.FPE +import restricted.fpe.FPEConst -val propFireHydrantBlock: BlockBehaviour.Properties = - BlockBehaviour.Properties.of(Material.HEAVY_METAL).strength(5.0F, 1200.0F).sound(SoundType.ANVIL).noOcclusion() - -object FireHydrantBlock : HorizontalDirectionalBlock(propFireHydrantBlock) { +object FireHydrantBlock : HorizontalDirectionalBlock(FPEConst.BlockConst.FireHydrantProp) { private val shape = Block.box(2.0, 0.0, 2.0, 14.0, 26.0, 14.0) init { diff --git a/src/main/kotlin/restricted/fpe/block/FireSprinklerBlock.kt b/src/main/kotlin/restricted/fpe/block/FireSprinklerBlock.kt new file mode 100644 index 0000000..8a6c08b --- /dev/null +++ b/src/main/kotlin/restricted/fpe/block/FireSprinklerBlock.kt @@ -0,0 +1,66 @@ +package restricted.fpe.block + +import net.minecraft.core.BlockPos +import net.minecraft.core.particles.ParticleTypes +import net.minecraft.world.level.Level +import net.minecraft.world.level.block.BaseEntityBlock +import net.minecraft.world.level.block.entity.* +import net.minecraft.world.level.block.state.BlockState +import net.minecraft.world.phys.Vec3 +import restricted.fpe.* +import restricted.fpe.block.entity.FireSprinklerBlockEntity +import restricted.fpe.extinguish.ExtinguishContext +import restricted.fpe.extinguish.ExtinguishContext.Companion.process +import restricted.fpe.extinguish.ExtinguishType + +object FireSprinklerBlock : BaseEntityBlock(FPEConst.BlockConst.FireSprinklerProp) { + + override fun newBlockEntity(pPos: BlockPos, pState: BlockState): BlockEntity? { + return FPE.BlockEntityTypes.FireSprinkler.create(pPos, pState) + } + + override fun getTicker( + pLevel: Level, + pState: BlockState, + pBlockEntityType: BlockEntityType + ): BlockEntityTicker? { + return createTickerHelper(pBlockEntityType, FPE.BlockEntityTypes.FireSprinkler, ::onTick) + } + + @Suppress("UNUSED_PARAMETER") + fun onTick(level: Level, pos: BlockPos, state: BlockState, be: FireSprinklerBlockEntity) { + level.runOnRemote { + if(be.waterSprinkling) { + be.ticks += 5 + if(be.ticks >= 900) { + be.waterSprinkling = false + be.overloaded = true + } + } else { + if(be.ticks > 0) { + be.ticks -= 3 + } + if(be.ticks < 50) { + be.overloaded = false + } + } + + // 重新设置模式 + val charged = level.hasNeighborSignal(pos) + if(!be.overloaded && charged) { // 未过载 + 激活 => 喷淋模式 + be.waterSprinkling = true + } + if(be.waterSprinkling && be.ticks >= 300 && !charged) { // 喷淋模式 + 未激活 => 冷却模式 + be.waterSprinkling = false + } + + if(be.waterSprinkling) { + ExtinguishContext(level, pos, 3, ExtinguishType.WATER).process() + sendParticles(ParticleTypes.RAIN, pos.vec3.add(0.0, -2.5, 0.0), 100, 0.2, offset = Vec3(4.0, 2.5, 4.0)) + } + if(be.overloaded) { + sendParticles(ParticleTypes.SMOKE, pos.vec3.add(0.0, 0.15, 0.0), 5, 0.2) + } + } + } +} \ No newline at end of file diff --git a/src/main/kotlin/restricted/fpe/block/entity/FireDetectorBlockEntity.kt b/src/main/kotlin/restricted/fpe/block/entity/FireDetectorBlockEntity.kt new file mode 100644 index 0000000..4bc3527 --- /dev/null +++ b/src/main/kotlin/restricted/fpe/block/entity/FireDetectorBlockEntity.kt @@ -0,0 +1,32 @@ +package restricted.fpe.block.entity + +import net.minecraft.core.BlockPos +import net.minecraft.nbt.CompoundTag +import net.minecraft.world.level.block.entity.BlockEntity +import net.minecraft.world.level.block.state.BlockState +import restricted.fpe.FPE +import restricted.fpe.buildCompoundTag + +class FireDetectorBlockEntity(pos: BlockPos, state: BlockState) : + BlockEntity(FPE.BlockEntityTypes.FireDetector, pos, state), IFireProtectBlockEntity { + + override var needSync: Boolean = false + + var fireDetected: Boolean = false + + override fun getUpdateTag(): CompoundTag { + return buildCompoundTag { + putBoolean("fire", fireDetected) + } + } + + override fun saveAdditional(pTag: CompoundTag) { + super.saveAdditional(pTag) + pTag.putBoolean("fire", fireDetected) + } + + override fun load(pTag: CompoundTag) { + super.load(pTag) + fireDetected = pTag.getBoolean("fire") + } +} \ No newline at end of file diff --git a/src/main/kotlin/restricted/fpe/block/entity/FireSprinklerBlockEntity.kt b/src/main/kotlin/restricted/fpe/block/entity/FireSprinklerBlockEntity.kt new file mode 100644 index 0000000..383a369 --- /dev/null +++ b/src/main/kotlin/restricted/fpe/block/entity/FireSprinklerBlockEntity.kt @@ -0,0 +1,44 @@ +package restricted.fpe.block.entity + +import net.minecraft.core.BlockPos +import net.minecraft.nbt.CompoundTag +import net.minecraft.world.level.block.entity.BlockEntity +import net.minecraft.world.level.block.state.BlockState +import restricted.fpe.FPE +import restricted.fpe.buildCompoundTag + +class FireSprinklerBlockEntity(pos: BlockPos, state: BlockState) : + BlockEntity(FPE.BlockEntityTypes.FireSprinkler, pos, state), IFireProtectBlockEntity { + + override var needSync: Boolean = false + + // 模式 - TRUE 洒水模式 FALSE 冷却模式/等待模式 + var waterSprinkling = false + + // 计时器 - 洒水模式时向上涨,直到 300tick(15s) 切换模式 + // - 冷却模式时向下降,直到 0tick + var ticks = 0 + + var overloaded = false + + val idle: Boolean get() = !waterSprinkling && ticks == 0 + + override fun getUpdateTag(): CompoundTag { + return buildCompoundTag { + putBoolean("mode", waterSprinkling) + putInt("value", ticks) + } + } + + override fun saveAdditional(pTag: CompoundTag) { + super.saveAdditional(pTag) + pTag.putBoolean("mode", waterSprinkling) + pTag.putInt("value", ticks) + } + + override fun load(pTag: CompoundTag) { + super.load(pTag) + waterSprinkling = pTag.getBoolean("mode") + ticks = pTag.getInt("value") + } +} \ No newline at end of file diff --git a/src/main/kotlin/restricted/fpe/block/entity/IFireProtectBlockEntity.kt b/src/main/kotlin/restricted/fpe/block/entity/IFireProtectBlockEntity.kt new file mode 100644 index 0000000..a8cf4d2 --- /dev/null +++ b/src/main/kotlin/restricted/fpe/block/entity/IFireProtectBlockEntity.kt @@ -0,0 +1,35 @@ +package restricted.fpe.block.entity + +import net.minecraft.network.protocol.game.ClientboundBlockEntityDataPacket +import net.minecraft.world.level.ChunkPos +import net.minecraft.world.level.block.entity.BlockEntity +import restricted.fpe.letOnRemote + +interface IFireProtectBlockEntity { + + var needSync: Boolean + + fun tickSync(blockEntity: BlockEntity) { + if(needSync) { + executeSync(blockEntity) + needSync = false + } + } + + private fun executeSync(blockEntity: BlockEntity) { + blockEntity.level?.letOnRemote { serverLevel -> + ClientboundBlockEntityDataPacket.create(blockEntity).let { packet -> + serverLevel.chunkSource.chunkMap.getPlayers(ChunkPos(blockEntity.blockPos), false).forEach { player -> + player.connection.send(packet) + } + } + } + } + + companion object { + fun T.tickSync() { + if(this is IFireProtectBlockEntity) { tickSync(this) } + } + } + +} \ No newline at end of file diff --git a/src/main/kotlin/restricted/fpe/enchant/FireWalkerEnchant.kt b/src/main/kotlin/restricted/fpe/enchant/FireWalkerEnchant.kt index 816e4b0..a6295e4 100644 --- a/src/main/kotlin/restricted/fpe/enchant/FireWalkerEnchant.kt +++ b/src/main/kotlin/restricted/fpe/enchant/FireWalkerEnchant.kt @@ -1,12 +1,16 @@ package restricted.fpe.enchant import net.minecraft.world.entity.EquipmentSlot -import net.minecraft.world.item.enchantment.Enchantment -import net.minecraft.world.item.enchantment.EnchantmentCategory +import net.minecraft.world.item.enchantment.* object FireWalkerEnchant: Enchantment(Rarity.RARE, EnchantmentCategory.ARMOR_FEET, arrayOf(EquipmentSlot.FEET)) { override fun getMaxLevel(): Int = 3 override fun getMinCost(pLevel: Int): Int = pLevel * 10 override fun getMaxCost(pLevel: Int): Int = getMinCost(pLevel) + 15 + + override fun checkCompatibility(other: Enchantment): Boolean { + if(other != Enchantments.FROST_WALKER) return false + return true + } } \ No newline at end of file diff --git a/src/main/kotlin/restricted/fpe/enchant/SpreadingFireEnchant.kt b/src/main/kotlin/restricted/fpe/enchant/SpreadingFireEnchant.kt index 455992c..b679a63 100644 --- a/src/main/kotlin/restricted/fpe/enchant/SpreadingFireEnchant.kt +++ b/src/main/kotlin/restricted/fpe/enchant/SpreadingFireEnchant.kt @@ -5,10 +5,9 @@ import net.minecraft.world.item.BowItem import net.minecraft.world.item.CrossbowItem import net.minecraft.world.item.enchantment.Enchantment import net.minecraft.world.item.enchantment.EnchantmentCategory +import restricted.fpe.FPEConst.EnchantCategory.BowAndCrossbowCategory import restricted.fpe.potion.SpreadingFireEffect -val BowAndCrossbowCategory: EnchantmentCategory = EnchantmentCategory.create("bow_and_crossbow") { it is BowItem || it is CrossbowItem } - object SpreadingFireEnchant: Enchantment(Rarity.VERY_RARE, BowAndCrossbowCategory, arrayOf(EquipmentSlot.MAINHAND)) { override fun getMaxLevel(): Int = 5 diff --git a/src/main/kotlin/restricted/fpe/extinguish/BuiltInRecipes.kt b/src/main/kotlin/restricted/fpe/extinguish/BuiltInRecipes.kt new file mode 100644 index 0000000..6979e01 --- /dev/null +++ b/src/main/kotlin/restricted/fpe/extinguish/BuiltInRecipes.kt @@ -0,0 +1,91 @@ +package restricted.fpe.extinguish + +import net.minecraft.core.particles.ParticleTypes +import net.minecraft.sounds.SoundEvents +import net.minecraft.sounds.SoundSource +import net.minecraft.world.entity.EntityType +import net.minecraft.world.entity.MobSpawnType +import net.minecraft.world.entity.item.ItemEntity +import net.minecraft.world.entity.monster.MagmaCube +import net.minecraft.world.item.ItemStack +import net.minecraft.world.level.block.state.properties.BlockStateProperties +import restricted.fpe.* +import restricted.fpe.extinguish.ExtinguishRecipe.MiniBlockState.Builder.Companion.buildMiniState +import java.lang.reflect.Modifier + +object BuiltInRecipes { + + fun register() { + logger.debug("Register Extinguish Recipes") + + ExtinguishRecipe.registerBlock(MinecraftBlocks.FIRE.buildMiniState(), ExtinguishRecipe.directly()) + ExtinguishRecipe.registerBlock(MinecraftBlocks.SOUL_FIRE.buildMiniState(), ExtinguishRecipe.directly()) + ExtinguishRecipe.registerBlock(MinecraftBlocks.CAMPFIRE.buildMiniState { with(BlockStateProperties.LIT, true) }, + ExtinguishRecipe.replaceWithBlock( + MinecraftBlocks.CAMPFIRE.defaultBlockState().setValue(BlockStateProperties.LIT, false) + ) + ) + ExtinguishRecipe.registerBlock(MinecraftBlocks.SOUL_CAMPFIRE.buildMiniState { with(BlockStateProperties.LIT, true) }, + ExtinguishRecipe.replaceWithBlock( + MinecraftBlocks.SOUL_CAMPFIRE.defaultBlockState().setValue(BlockStateProperties.LIT, false) + ) + ) + + ExtinguishRecipe.builder(EntityType.BLAZE) { + dryIce { ctx, entity -> + ctx.level.runOnRemote { + if(entity.isAlive) { + entity.hurt(FPEConst.DamageSourceConst.Extinguish, 100.0F) + val itemEntity = ItemEntity(this, entity.x, entity.y, entity.z, ItemStack(MinecraftItems.BLAZE_ROD, (6..8).random())) + addFreshEntity(itemEntity) + } + } + } + otherwise { ctx, entity -> + ctx.level.runOnRemote { + sendParticles(ParticleTypes.SMOKE, entity.eyePosition, 20, 0.2) + } + } + } + + ExtinguishRecipe.builder(EntityType.MAGMA_CUBE) { + water { ctx, magma -> + ctx.level.runOnRemote { + if(magma is MagmaCube) { + playSound(null, magma, SoundEvents.WATER_AMBIENT, SoundSource.PLAYERS, 1.0F, 1.0F) + sendParticles(ParticleTypes.EXPLOSION, magma.eyePosition, 20, 0.2) + magma.tags + val slime = EntityType.SLIME.create(this, null, null, ctx.player, magma.onPos, MobSpawnType.TRIGGERED, true, true)!! + slime.yBodyRot = magma.yBodyRot + magma.discard() + addFreshEntity(slime) + } + } + } + } + + EntityType::class.java.declaredFields.forEach { + runCatching { + it.trySetAccessible() + if(Modifier.isStatic(it.modifiers) && Modifier.isFinal(it.modifiers) && it.type == EntityType::class.java) { + ExtinguishRecipe.registerEntity(it.get(null) as EntityType<*>, ExtinguishType.WATER) { _, entity -> + entity.clearFire() + } + } + }.onFailure { error -> + logger.warn("Unable to register the Water-Extinguish-Fire recipe for ${it.name}", error) + } + } + + ExtinguishRecipe.recipes.cellSet().forEach { (state, type, func) -> + logger.debug("[BlockExtinguishRecipe] $state & $type => ${func.hashCode()}") + } + + ExtinguishRecipe.recipesEntity.cellSet().forEach { (entityType, type, func) -> + logger.debug("[EntityExtinguishRecipe] ${entityType.registryName} & $type => ${func.hashCode()}") + } + + logger.debug("Done register Extinguish Recipes") + } + +} \ No newline at end of file diff --git a/src/main/kotlin/restricted/fpe/extinguish/ExtinguishContext.kt b/src/main/kotlin/restricted/fpe/extinguish/ExtinguishContext.kt index 72273bc..fe8c837 100644 --- a/src/main/kotlin/restricted/fpe/extinguish/ExtinguishContext.kt +++ b/src/main/kotlin/restricted/fpe/extinguish/ExtinguishContext.kt @@ -5,10 +5,11 @@ import net.minecraft.world.entity.player.Player import net.minecraft.world.item.ItemStack import net.minecraft.world.level.Level import net.minecraft.world.level.levelgen.structure.BoundingBox +import restricted.fpe.FPE import restricted.fpe.boundingBoxOfCenter data class ExtinguishContext( - val world: Level, + val level: Level, val centerPos: BlockPos, val size: Int, val type: ExtinguishType, @@ -17,4 +18,8 @@ data class ExtinguishContext( val itemstack: ItemStack? = null ) { val boundingBox: BoundingBox get() = boundingBoxOfCenter(centerPos, size, size, size) + + companion object { + fun ExtinguishContext.process() = FPE.extinguishFire(this) + } } \ No newline at end of file diff --git a/src/main/kotlin/restricted/fpe/extinguish/ExtinguishRecipe.kt b/src/main/kotlin/restricted/fpe/extinguish/ExtinguishRecipe.kt index ded200d..28c96c5 100644 --- a/src/main/kotlin/restricted/fpe/extinguish/ExtinguishRecipe.kt +++ b/src/main/kotlin/restricted/fpe/extinguish/ExtinguishRecipe.kt @@ -1,14 +1,23 @@ +@file:Suppress("unused") + package restricted.fpe.extinguish import com.google.common.collect.HashBasedTable import com.google.common.collect.Table import net.minecraft.core.BlockPos +import net.minecraft.core.particles.ParticleTypes +import net.minecraft.world.entity.Entity +import net.minecraft.world.entity.EntityType import net.minecraft.world.level.block.Block import net.minecraft.world.level.block.state.BlockState import net.minecraft.world.level.block.state.properties.Property -import restricted.fpe.component1 -import restricted.fpe.component2 -import restricted.fpe.component3 +import restricted.fpe.* +import restricted.fpe.extinguish.ExtinguishRecipe.MiniBlockState.Builder.Companion.buildMiniState +import restricted.fpe.item.FireExtinguisherItem +import thedarkcolour.kotlinforforge.kotlin.enumMapOf +import kotlin.collections.component1 +import kotlin.collections.component2 +import kotlin.collections.set /** * 将灭火视为合成,方块类型和灭火类型得到灭火逻辑。 @@ -18,15 +27,18 @@ object ExtinguishRecipe { data class MiniBlockState(val block: Block, val states: Map, *>) { fun apply(blockState: BlockState): Boolean { - if(block != blockState.block) return false - if(states.any { (property, value) -> blockState.getValue(property) != value }) return false + if(block != blockState.block) { + return false + } + if(states.any { (property, value) -> (blockState.getValue(property) != value) }) return false return true } class Builder(val block: Block) { private val states = mutableMapOf, Any?>() - fun > with(property: Property, value: T) = apply { states[property] = value } + fun > with(property: Property, value: T) = apply { states[property] = value } fun build(): MiniBlockState = MiniBlockState(block, states) + companion object { fun Block.buildMiniState(block: Builder.() -> Unit = {}): MiniBlockState = Builder(this).apply(block).build() @@ -34,28 +46,168 @@ object ExtinguishRecipe { } } - internal val recipes: Table = HashBasedTable.create() + internal val recipes: Table = HashBasedTable.create() + internal val recipesEntity: Table, ExtinguishType, ExtinguishEntityFunction> = HashBasedTable.create() + + internal val invalidBlocks = mutableListOf( + MinecraftBlocks.AIR + ) - fun register( + //////// REGISTER METHODS + + fun registerBlock( blockState: MiniBlockState, - func: ExtinguishingFunction - ) = register(blockState, enumValues(), func) + func: ExtinguishBlockFunction + ) = registerBlock(blockState, ExtinguishType.ALL, func) - fun register(blockState: MiniBlockState, types: Array, func: ExtinguishingFunction) = - types.forEach { register(blockState, it, func) } + fun registerBlock(blockState: MiniBlockState, types: Array, func: ExtinguishBlockFunction) = + types.forEach { registerBlock(blockState, it, func) } - fun register( + fun registerBlock( blockState: MiniBlockState, extinguishType: ExtinguishType, - block: ExtinguishingFunction + func: ExtinguishBlockFunction + ) { + recipes.put(blockState, extinguishType, func) + } + + fun registerEntity( + entity: EntityType<*>, + func: ExtinguishEntityFunction + ) = registerEntity(entity, ExtinguishType.ALL, func) + + fun registerEntity( + entityType: EntityType<*>, + extinguishTypes: Array, + func: ExtinguishEntityFunction + ) = extinguishTypes.forEach { registerEntity(entityType, it, func) } + + fun registerEntity( + entityType: EntityType<*>, + extinguishType: ExtinguishType, + func: ExtinguishEntityFunction ) { - recipes.put(blockState, extinguishType, block) + recipesEntity.put(entityType, extinguishType, func) + } + + operator fun get(blockState: BlockState, extinguishType: ExtinguishType): ExtinguishBlockFunction? { + if(blockState.block in invalidBlocks) return null + + return recipes.column(extinguishType) + .firstNotNullOfOrNull { (miniState, value) -> + if(miniState.apply(blockState)) value else null + } } - operator fun get(blockState: BlockState, extinguishType: ExtinguishType): ExtinguishingFunction? { - return recipes.cellSet().firstOrNull { (miniState, type, _) -> miniState.apply(blockState) && type == extinguishType }?.value + fun getForEntity( + entityType: EntityType, + extinguishType: ExtinguishType + ): ExtinguishEntityFunction? { + return recipesEntity[entityType, extinguishType] + } + + //////// FAST FUNCTIONS + + private val DIRECTLY_EXTINGUISH: ExtinguishBlockFunction = { ctx, _, pos -> + val canExtinguish = (ctx.itemstack == null) || (ctx.itemstack.item == FPE.Items.FireExtinguisher && FireExtinguisherItem.canExtinguishFire(ctx, pos)) + + if(canExtinguish) { + ctx.level.removeBlock(pos, false) + } + ctx.level.runOnRemote { + sendParticles(ParticleTypes.CLOUD, pos.vec3, (1..20).random(), 0.2) + } + } + + fun directly(): ExtinguishBlockFunction = DIRECTLY_EXTINGUISH + + fun replaceWithBlock(newState: BlockState): ExtinguishBlockFunction = { ctx, _, pos -> + val canExtinguish = (ctx.itemstack == null) || (ctx.itemstack.item == FPE.Items.FireExtinguisher && FireExtinguisherItem.canExtinguishFire(ctx, pos)) + + if(canExtinguish) { + ctx.level.setBlockAndUpdate(pos, newState) + } + ctx.level.runOnRemote { + sendParticles(ParticleTypes.CLOUD, pos.vec3, (1..20).random(), 0.2) + } + } + + //////// BUILDER + + internal fun builder(block: Block, func: BuilderForBlock.() -> Unit) = BuilderForBlock(block).apply(func) + internal fun builder(entityType: EntityType, func: BuilderForEntity.() -> Unit) = + BuilderForEntity(entityType).apply(func).build() + + internal class BuilderForBlock(val block: Block) { + + fun withState(func: BuilderForMiniBlockState.() -> Unit) { + BuilderForMiniBlockState(block.buildMiniState()).apply(func).build() + } + + fun > withState(vararg pairs: Pair, T>, func: BuilderForMiniBlockState.() -> Unit) { + val miniState = block.buildMiniState { + pairs.forEach { + with(it.first, it.second) + } + } + BuilderForMiniBlockState(miniState).apply(func).build() + } + + } + + internal class BuilderForMiniBlockState(val miniBlockState: MiniBlockState) { + + private val conditions = enumMapOf() + + fun typed(type: ExtinguishType, func: ExtinguishBlockFunction) { + conditions[type] = func + } + + fun dryChemical(func: ExtinguishBlockFunction) = typed(ExtinguishType.DRY_CHEMICAL, func) + fun foams(func: ExtinguishBlockFunction) = typed(ExtinguishType.FOAMS, func) + fun water(func: ExtinguishBlockFunction) = typed(ExtinguishType.WATER, func) + fun dryIce(func: ExtinguishBlockFunction) = typed(ExtinguishType.DRY_ICE, func) + + fun otherwise(func: ExtinguishBlockFunction) { + ExtinguishType.ALL.forEach { + conditions.putIfAbsent(it, func) + } + } + + fun build() { + conditions.forEach { (type, func) -> + registerBlock(miniBlockState, type, func) + } + } + } + + internal class BuilderForEntity(val entityType: EntityType) { + + private val conditions = enumMapOf() + + fun typed(type: ExtinguishType, func: ExtinguishEntityFunction) { + conditions[type] = func + } + + fun dryChemical(func: ExtinguishEntityFunction) = typed(ExtinguishType.DRY_CHEMICAL, func) + fun foams(func: ExtinguishEntityFunction) = typed(ExtinguishType.FOAMS, func) + fun water(func: ExtinguishEntityFunction) = typed(ExtinguishType.WATER, func) + fun dryIce(func: ExtinguishEntityFunction) = typed(ExtinguishType.DRY_ICE, func) + + fun otherwise(func: ExtinguishEntityFunction) { + ExtinguishType.ALL.forEach { + conditions.putIfAbsent(it, func) + } + } + + fun build() { + conditions.forEach { (type, func) -> + registerEntity(entityType, type, func) + } + } } } -typealias ExtinguishingFunction = (ExtinguishContext, BlockState, BlockPos) -> Unit \ No newline at end of file +typealias ExtinguishBlockFunction = (ExtinguishContext, BlockState, BlockPos) -> Unit +typealias ExtinguishEntityFunction = (ExtinguishContext, Entity) -> Unit \ No newline at end of file diff --git a/src/main/kotlin/restricted/fpe/extinguish/ExtinguishType.kt b/src/main/kotlin/restricted/fpe/extinguish/ExtinguishType.kt index bdda7b1..bbf0cfc 100644 --- a/src/main/kotlin/restricted/fpe/extinguish/ExtinguishType.kt +++ b/src/main/kotlin/restricted/fpe/extinguish/ExtinguishType.kt @@ -1,8 +1,14 @@ package restricted.fpe.extinguish enum class ExtinguishType { - DryChemical, // 干粉 - Foams, // 泡沫 - Water, // 水 - DryIce // 干冰 + DRY_CHEMICAL, // 干粉 + FOAMS, // 泡沫 + WATER, // 水 + DRY_ICE, // 干冰 + + NONE; + + companion object { + val ALL = arrayOf(DRY_CHEMICAL, FOAMS, WATER, DRY_ICE) + } } \ No newline at end of file diff --git a/src/main/kotlin/restricted/fpe/item/FireExtinguisherItem.kt b/src/main/kotlin/restricted/fpe/item/FireExtinguisherItem.kt index 7866a30..23c63a8 100644 --- a/src/main/kotlin/restricted/fpe/item/FireExtinguisherItem.kt +++ b/src/main/kotlin/restricted/fpe/item/FireExtinguisherItem.kt @@ -1,23 +1,95 @@ package restricted.fpe.item +import net.minecraft.core.BlockPos +import net.minecraft.core.NonNullList +import net.minecraft.nbt.CompoundTag import net.minecraft.world.InteractionHand import net.minecraft.world.InteractionResultHolder import net.minecraft.world.entity.LivingEntity import net.minecraft.world.entity.player.Player import net.minecraft.world.item.* import net.minecraft.world.level.Level -import restricted.fpe.FPE -import restricted.fpe.extinguish.ExtinguishContext -import restricted.fpe.extinguish.ExtinguishType -import restricted.fpe.pos +import net.minecraft.world.level.dimension.DimensionType +import restricted.fpe.* +import restricted.fpe.extinguish.* -private val prop = Item.Properties().rarity(Rarity.UNCOMMON).tab(FPE.Tabs.Default).stacksTo(1).durability(15000) +object FireExtinguisherItem : Item(FPEConst.ItemConst.FireExtinguisherProp) { -object FireExtinguisherItem: Item(prop) { + const val TAG_EXTINGUISHER = "$ModId:extinguisher" + const val TAG_EXTINGUISHER_TYPE = "type" + const val TAG_EXTINGUISHER_LEVEL = "level" - private fun getExtinguisherLevel(world: Level, stack: ItemStack): Int = 3 + val DRY_ICE_INEXTINGUISHABLE = arrayOf( + MinecraftBlocks.BEDROCK, + MinecraftBlocks.NETHERRACK + ) - private fun getExtinguisherType(): ExtinguishType = ExtinguishType.DryChemical + val ItemStack.extinguisherTag: CompoundTag get() = getOrCreateTagElement(TAG_EXTINGUISHER) + + var CompoundTag.extinguisherType: ExtinguishType + get() = enumValueOrNull(getString(TAG_EXTINGUISHER_TYPE)) ?: ExtinguishType.NONE + set(value) = putString(TAG_EXTINGUISHER_TYPE, value.toString()) + + var CompoundTag.extinguishingLevel: Int + get() = getInt(TAG_EXTINGUISHER_LEVEL) ifZero 3 + set(value) = putInt(TAG_EXTINGUISHER_LEVEL, value) + + val DryChemicalTyped: ItemStack = defaultInstance.copy().apply { + getOrCreateTagElement(TAG_EXTINGUISHER).also { + it.extinguisherType = ExtinguishType.DRY_CHEMICAL + } + } + + val FoamsTyped: ItemStack = defaultInstance.copy().apply { + getOrCreateTagElement(TAG_EXTINGUISHER).also { + it.extinguisherType = ExtinguishType.FOAMS + } + } + + val WaterTyped: ItemStack = defaultInstance.copy().apply { + getOrCreateTagElement(TAG_EXTINGUISHER).also { + it.extinguisherType = ExtinguishType.WATER + } + } + + val DryIceTyped: ItemStack = defaultInstance.copy().apply { + getOrCreateTagElement(TAG_EXTINGUISHER).also { + it.extinguisherType = ExtinguishType.DRY_ICE + } + } + + override fun fillItemCategory(pCategory: CreativeModeTab, items: NonNullList) { + if(allowdedIn(pCategory)) { + items += DryChemicalTyped.copy() + items += FoamsTyped.copy() + items += WaterTyped.copy() + items += DryIceTyped.copy() + } + } + + private fun getExtinguisherLevel(world: Level, stack: ItemStack): Int { + val type = getExtinguisherType(stack) + if(type == ExtinguishType.FOAMS && world.dimensionType() == DimensionType.DEFAULT_NETHER) { + return 0 + } + return stack.extinguisherTag.extinguishingLevel + } + + private fun getExtinguisherType(stack: ItemStack): ExtinguishType = stack.extinguisherTag.extinguisherType + + /** + * @see ExtinguishRecipe.DIRECTLY_EXTINGUISH + */ + fun canExtinguishFire(ctx: ExtinguishContext, pos: BlockPos): Boolean { + if(ctx.itemstack?.extinguisherTag?.extinguisherType == ExtinguishType.DRY_ICE) { + return ctx.level.getBlockState(pos.below()).block !in DRY_ICE_INEXTINGUISHABLE + } + return true + } + + override fun getDescriptionId(itemstack: ItemStack): String { + return "${descriptionId}.${itemstack.extinguisherTag.extinguisherType.name.lowercase()}" + } override fun getUseDuration(pStack: ItemStack): Int { return 10 @@ -43,7 +115,8 @@ object FireExtinguisherItem: Item(prop) { val hit = entity.pick(10.0, 1.0F, false) val extinguishLoc = hit.location.pos val extinguishLevel = getExtinguisherLevel(world, stack) - val ctx = ExtinguishContext(world, extinguishLoc, extinguishLevel, getExtinguisherType(), player = entity) + val ctx = + ExtinguishContext(world, extinguishLoc, extinguishLevel, getExtinguisherType(stack), player = entity, itemstack = stack) FPE.extinguishFire(ctx) } super.releaseUsing(stack, world, entity, chargedTime) diff --git a/src/main/kotlin/restricted/fpe/item/FireItem.kt b/src/main/kotlin/restricted/fpe/item/FireItem.kt index b56d061..3a3cb20 100644 --- a/src/main/kotlin/restricted/fpe/item/FireItem.kt +++ b/src/main/kotlin/restricted/fpe/item/FireItem.kt @@ -1,12 +1,9 @@ package restricted.fpe.item import net.minecraft.world.item.Item -import net.minecraft.world.item.Rarity -import restricted.fpe.FPE +import restricted.fpe.FPEConst -private val prop = Item.Properties().rarity(Rarity.COMMON).tab(FPE.Tabs.Default) - -object FireItem: Item(prop) { +object FireItem: Item(FPEConst.ItemConst.DefaultItemProp) { // prevent being fired override fun isFireResistant(): Boolean = true diff --git a/src/main/kotlin/restricted/fpe/item/FurnaceFireProtectionDeviceItem.kt b/src/main/kotlin/restricted/fpe/item/FurnaceFireProtectionDeviceItem.kt new file mode 100644 index 0000000..81b7054 --- /dev/null +++ b/src/main/kotlin/restricted/fpe/item/FurnaceFireProtectionDeviceItem.kt @@ -0,0 +1,25 @@ +package restricted.fpe.item + +import net.minecraft.world.InteractionResult +import net.minecraft.world.item.Item +import net.minecraft.world.item.context.UseOnContext +import net.minecraft.world.level.block.entity.BlockEntityType +import restricted.fpe.FPEConst.ItemConst.DefaultNonStackableItemProp +import restricted.fpe.MinecraftBlocks + +object FurnaceFireProtectionDeviceItem: Item(DefaultNonStackableItemProp) { + + override fun useOn(ctx: UseOnContext): InteractionResult { + val level = ctx.level + val blockPos = ctx.clickedPos + val state = level.getBlockState(blockPos) + if(state.block == MinecraftBlocks.FURNACE) { + val furnaceEntity = level.getBlockEntity(blockPos, BlockEntityType.FURNACE) + if(furnaceEntity.isPresent) { + return InteractionResult.sidedSuccess(level.isClientSide) + } + } + return super.useOn(ctx) + } + +} \ No newline at end of file diff --git a/src/main/kotlin/restricted/fpe/potion/SpreadingFireEffect.kt b/src/main/kotlin/restricted/fpe/potion/SpreadingFireEffect.kt index 177eb18..936896f 100644 --- a/src/main/kotlin/restricted/fpe/potion/SpreadingFireEffect.kt +++ b/src/main/kotlin/restricted/fpe/potion/SpreadingFireEffect.kt @@ -6,22 +6,20 @@ import net.minecraft.world.effect.* import net.minecraft.world.entity.LivingEntity import net.minecraft.world.entity.ai.targeting.TargetingConditions import net.minecraft.world.phys.AABB -import restricted.fpe.FPE - -val SpreadingFireDamageSource = DamageSource("spreading_fire") - -private const val factorNextGenDuration = 8 -private const val sizeOfSpreading = 8.0 +import restricted.fpe.* object SpreadingFireEffect : MobEffect(MobEffectCategory.HARMFUL, 0x2524AB) { + private const val factorNextGenDuration = 8 + private const val sizeOfSpreading = 8.0 + fun instance(duration: Int, amplifier: Int) = MobEffectInstance(FPE.MobEffects.SpreadingFire, duration, amplifier) override fun isDurationEffectTick(pDuration: Int, pAmplifier: Int): Boolean = true override fun applyEffectTick(entity: LivingEntity, amp: Int) { val ampFactor = amp + 1 - entity.hurt(SpreadingFireDamageSource, 1.0F + ampFactor * 0.75F) + entity.hurt(FPEConst.DamageSourceConst.SpreadingFire, 1.0F + ampFactor * 0.75F) if(entity.health <= 0.0F) { // lv1=4; lv5=10 val size = ampFactor * 0.8 + 4.0 @@ -35,10 +33,8 @@ object SpreadingFireEffect : MobEffect(MobEffectCategory.HARMFUL, 0x2524AB) { } } - if(entity.level.isClientSide) { - entity.level.addParticle(ParticleTypes.FLAME, true, entity.x, entity.y + 1.5, entity.z, 0.0, 0.0, 0.0) + entity.level.runOnRemote { + sendParticles(ParticleTypes.FLAME, entity.position(), 5, 1.0) } - - // TODO: 烈焰粒子效果 } } \ No newline at end of file diff --git a/src/main/resources/META-INF/accesstransformer.cfg b/src/main/resources/META-INF/accesstransformer.cfg new file mode 100644 index 0000000..3d13a3c --- /dev/null +++ b/src/main/resources/META-INF/accesstransformer.cfg @@ -0,0 +1,4 @@ +public net.minecraft.world.level.dimension.DimensionType f_63848_ # DEFAULT_OVERWORLD +public net.minecraft.world.level.dimension.DimensionType f_63849_ # DEFAULT_NETHER +public net.minecraft.world.level.dimension.DimensionType f_63850_ # DEFAULT_END +# public net.minecraft.world.entity.monster.Slime m_7839_(IZ)V # setSize \ No newline at end of file diff --git a/src/main/resources/assets/fire_protection_equipment/blockstates/fire_detector.json b/src/main/resources/assets/fire_protection_equipment/blockstates/fire_detector.json new file mode 100644 index 0000000..d09cdea --- /dev/null +++ b/src/main/resources/assets/fire_protection_equipment/blockstates/fire_detector.json @@ -0,0 +1,11 @@ +{ + "variants": { + "facing=up": { + "model": "fire_protection_equipment:block/fire_detector" + }, + "facing=down": { + "model": "fire_protection_equipment:block/fire_detector", + "x": 180 + } + } +} \ No newline at end of file diff --git a/src/main/resources/assets/fire_protection_equipment/blockstates/fire_extinguishing_bomb.json b/src/main/resources/assets/fire_protection_equipment/blockstates/fire_extinguishing_bomb.json new file mode 100644 index 0000000..9c82a2a --- /dev/null +++ b/src/main/resources/assets/fire_protection_equipment/blockstates/fire_extinguishing_bomb.json @@ -0,0 +1,7 @@ +{ + "variants": { + "": { + "model": "fire_protection_equipment:block/fire_extinguishing_bomb" + } + } +} \ No newline at end of file diff --git a/src/main/resources/assets/fire_protection_equipment/models/block/fire_extinguishing_bomb.json b/src/main/resources/assets/fire_protection_equipment/models/block/fire_extinguishing_bomb.json new file mode 100644 index 0000000..1c40543 --- /dev/null +++ b/src/main/resources/assets/fire_protection_equipment/models/block/fire_extinguishing_bomb.json @@ -0,0 +1,8 @@ +{ + "parent": "minecraft:block/cube_bottom_top", + "textures": { + "top": "minecraft:block/tnt_top", + "bottom": "minecraft:block/tnt_bottom", + "side": "fire_protection_equipment:block/fire_extinguishing_bomb_side" + } +} \ No newline at end of file diff --git a/src/main/resources/assets/fire_protection_equipment/models/item/fire_detector.json b/src/main/resources/assets/fire_protection_equipment/models/item/fire_detector.json new file mode 100644 index 0000000..f7ae9ea --- /dev/null +++ b/src/main/resources/assets/fire_protection_equipment/models/item/fire_detector.json @@ -0,0 +1,3 @@ +{ + "parent": "fire_protection_equipment:block/fire_detector" +} \ No newline at end of file diff --git a/src/main/resources/assets/fire_protection_equipment/models/item/fire_extinguisher.json b/src/main/resources/assets/fire_protection_equipment/models/item/fire_extinguisher.json index f208ed7..8105705 100644 --- a/src/main/resources/assets/fire_protection_equipment/models/item/fire_extinguisher.json +++ b/src/main/resources/assets/fire_protection_equipment/models/item/fire_extinguisher.json @@ -1,9 +1,217 @@ { - "parent": "fire_protection_equipment:block/fire_extinguisher", - "display": { - "gui": { - "rotation": [0, 85, 5], - "scale": [0.8, 0.95, 0.8] - } - } + "credit": "Made with Blockbench", + "parent": "fire_hydrant", + "texture_size": [32, 32], + "textures": { + "0": "fire_protection_equipment:block/fire_extinguisher", + "particle": "fire_protection_equipment:block/fire_extinguisher" + }, + "elements": [ + { + "from": [6, 0, 6.125], + "to": [10, 10.5, 10.125], + "rotation": {"angle": 0, "axis": "y", "origin": [8, 0, 7.125]}, + "faces": { + "north": {"uv": [0, 0, 2, 5.5], "texture": "#0"}, + "east": {"uv": [2, 0, 4, 5.5], "texture": "#0"}, + "south": {"uv": [4, 0, 6, 5.5], "texture": "#0"}, + "west": {"uv": [0, 5.5, 2, 11], "texture": "#0"}, + "up": {"uv": [11.5, 7, 9.5, 5], "texture": "#0"}, + "down": {"uv": [11.5, 7, 9.5, 9], "texture": "#0"} + } + }, + { + "from": [9.5, 0, 6.625], + "to": [10.5, 10, 9.625], + "rotation": {"angle": 0, "axis": "y", "origin": [8, 0, 7.125]}, + "faces": { + "north": {"uv": [9.5, 9, 10, 14], "texture": "#0"}, + "east": {"uv": [2, 5.5, 3.5, 10.5], "texture": "#0"}, + "south": {"uv": [6.5, 10, 7, 15], "texture": "#0"}, + "west": {"uv": [3.5, 5.5, 5, 10.5], "texture": "#0"}, + "up": {"uv": [11, 4.5, 10.5, 3], "texture": "#0"}, + "down": {"uv": [4.5, 10.5, 4, 12], "texture": "#0"} + } + }, + { + "from": [6.5, 0, 9.625], + "to": [9.5, 10, 10.625], + "rotation": {"angle": 0, "axis": "y", "origin": [8, 0, 7.125]}, + "faces": { + "north": {"uv": [5, 5.5, 6.5, 10.5], "texture": "#0"}, + "east": {"uv": [7, 10, 7.5, 15], "texture": "#0"}, + "south": {"uv": [6, 0, 7.5, 5], "texture": "#0"}, + "west": {"uv": [7.5, 10, 8, 15], "texture": "#0"}, + "up": {"uv": [6, 11, 4.5, 10.5], "texture": "#0"}, + "down": {"uv": [12, 4.5, 10.5, 5], "texture": "#0"} + } + }, + { + "from": [6.5, 0, 5.625], + "to": [9.5, 10, 6.625], + "rotation": {"angle": 0, "axis": "y", "origin": [8, 0, 7.125]}, + "faces": { + "north": {"uv": [6.5, 5, 8, 10], "texture": "#0"}, + "east": {"uv": [8, 10, 8.5, 15], "texture": "#0"}, + "south": {"uv": [7.5, 0, 9, 5], "texture": "#0"}, + "west": {"uv": [8.5, 10, 9, 15], "texture": "#0"}, + "up": {"uv": [12, 9.5, 10.5, 9], "texture": "#0"}, + "down": {"uv": [12, 9.5, 10.5, 10], "texture": "#0"} + } + }, + { + "from": [5.5, 0, 6.625], + "to": [6.5, 10, 9.625], + "rotation": {"angle": 0, "axis": "y", "origin": [8, 0, 7.125]}, + "faces": { + "north": {"uv": [9, 10, 9.5, 15], "texture": "#0"}, + "east": {"uv": [8, 5, 9.5, 10], "texture": "#0"}, + "south": {"uv": [10, 9, 10.5, 14], "texture": "#0"}, + "west": {"uv": [9, 0, 10.5, 5], "texture": "#0"}, + "up": {"uv": [6.5, 12, 6, 10.5], "texture": "#0"}, + "down": {"uv": [11, 10, 10.5, 11.5], "texture": "#0"} + } + }, + { + "from": [6.5, 10, 6.625], + "to": [9.5, 11, 9.625], + "rotation": {"angle": 0, "axis": "y", "origin": [8, 0, 7.125]}, + "faces": { + "north": {"uv": [0, 11, 1.5, 11.5], "texture": "#0"}, + "east": {"uv": [11, 3, 12.5, 3.5], "texture": "#0"}, + "south": {"uv": [11, 3.5, 12.5, 4], "texture": "#0"}, + "west": {"uv": [11, 4, 12.5, 4.5], "texture": "#0"}, + "up": {"uv": [12, 1.5, 10.5, 0], "texture": "#0"}, + "down": {"uv": [12, 1.5, 10.5, 3], "texture": "#0"} + } + }, + { + "from": [7.5, 11, 7.625], + "to": [8.5, 13, 8.625], + "rotation": {"angle": 0, "axis": "y", "origin": [8, 0, 7.125]}, + "faces": { + "north": {"uv": [5, 11.5, 5.5, 12.5], "texture": "#0"}, + "east": {"uv": [11.5, 5, 12, 6], "texture": "#0"}, + "south": {"uv": [5.5, 11.5, 6, 12.5], "texture": "#0"}, + "west": {"uv": [11.5, 6, 12, 7], "texture": "#0"}, + "up": {"uv": [6.5, 5.5, 6, 5], "texture": "#0"}, + "down": {"uv": [1.5, 12, 1, 12.5], "texture": "#0"} + } + }, + { + "from": [7.75, 12, 6.625], + "to": [8.25, 12.5, 8.125], + "rotation": {"angle": 0, "axis": "y", "origin": [8, 0, 7.125]}, + "faces": { + "north": {"uv": [2, 12, 2.5, 12.5], "texture": "#0"}, + "east": {"uv": [11.5, 7, 12.5, 7.5], "texture": "#0"}, + "south": {"uv": [12, 2, 12.5, 2.5], "texture": "#0"}, + "west": {"uv": [11.5, 7.5, 12.5, 8], "texture": "#0"}, + "up": {"uv": [12, 9, 11.5, 8], "texture": "#0"}, + "down": {"uv": [11, 11.5, 10.5, 12.5], "texture": "#0"} + } + }, + { + "from": [7.5, 11.75, 5.625], + "to": [8.5, 12.75, 7.125], + "rotation": {"angle": 0, "axis": "y", "origin": [8, 0, 7.125]}, + "faces": { + "north": {"uv": [2.5, 12, 3, 12.5], "texture": "#0"}, + "east": {"uv": [11.5, 10.5, 12.5, 11], "texture": "#0"}, + "south": {"uv": [12, 2.5, 12.5, 3], "texture": "#0"}, + "west": {"uv": [11.5, 11, 12.5, 11.5], "texture": "#0"}, + "up": {"uv": [12, 12.5, 11.5, 11.5], "texture": "#0"}, + "down": {"uv": [0.5, 12, 0, 13], "texture": "#0"} + } + }, + { + "from": [7.25, 11.5, 5.625], + "to": [8.75, 13, 6.125], + "rotation": {"angle": 0, "axis": "y", "origin": [8, 0, 7.125]}, + "faces": { + "north": {"uv": [2, 10.5, 3, 11.5], "texture": "#0"}, + "east": {"uv": [12, 0, 12.5, 1], "texture": "#0"}, + "south": {"uv": [3, 10.5, 4, 11.5], "texture": "#0"}, + "west": {"uv": [0.5, 12, 1, 13], "texture": "#0"}, + "up": {"uv": [13, 1.5, 12, 1], "texture": "#0"}, + "down": {"uv": [13, 1.5, 12, 2], "texture": "#0"} + } + }, + { + "from": [7, 12, 7.875], + "to": [7.5, 12.5, 8.375], + "rotation": {"angle": 0, "axis": "y", "origin": [8, 0, 7.125]}, + "faces": { + "north": {"uv": [3, 12, 3.5, 12.5], "texture": "#0"}, + "east": {"uv": [4, 12, 4.5, 12.5], "texture": "#0"}, + "south": {"uv": [12, 4.5, 12.5, 5], "texture": "#0"}, + "west": {"uv": [12, 5, 12.5, 5.5], "texture": "#0"}, + "up": {"uv": [12.5, 6, 12, 5.5], "texture": "#0"}, + "down": {"uv": [6.5, 12, 6, 12.5], "texture": "#0"} + } + }, + { + "from": [7, 11.75, 7.625], + "to": [7.25, 12.75, 8.625], + "rotation": {"angle": 0, "axis": "y", "origin": [8, 0, 7.125]}, + "faces": { + "north": {"uv": [12, 6, 12.5, 6.5], "texture": "#0"}, + "east": {"uv": [12, 6.5, 12.5, 7], "texture": "#0"}, + "south": {"uv": [12, 8, 12.5, 8.5], "texture": "#0"}, + "west": {"uv": [12, 8.5, 12.5, 9], "texture": "#0"}, + "up": {"uv": [12.5, 9.5, 12, 9], "texture": "#0"}, + "down": {"uv": [12.5, 9.5, 12, 10], "texture": "#0"} + } + }, + { + "from": [7.75, 12.5, 8.125], + "to": [8.25, 12.75, 11.125], + "rotation": {"angle": 0, "axis": "y", "origin": [8, 0, 7.125]}, + "faces": { + "north": {"uv": [11, 12, 11.5, 12.5], "texture": "#0"}, + "east": {"uv": [4.5, 11, 6, 11.5], "texture": "#0"}, + "south": {"uv": [12, 11.5, 12.5, 12], "texture": "#0"}, + "west": {"uv": [11, 10, 12.5, 10.5], "texture": "#0"}, + "up": {"uv": [2, 12.5, 1.5, 11], "texture": "#0"}, + "down": {"uv": [11.5, 10.5, 11, 12], "texture": "#0"} + } + }, + { + "from": [7.75, 11.30585, 12.93992], + "to": [8.25, 11.55585, 15.68992], + "rotation": {"angle": -22.5, "axis": "x", "origin": [8, 0, 7.125]}, + "faces": { + "north": {"uv": [12, 12, 12.5, 12.5], "texture": "#0"}, + "east": {"uv": [0, 11.5, 1.5, 12], "texture": "#0"}, + "south": {"uv": [12.5, 0, 13, 0.5], "texture": "#0"}, + "west": {"uv": [2, 11.5, 3.5, 12], "texture": "#0"}, + "up": {"uv": [4, 13, 3.5, 11.5], "texture": "#0"}, + "down": {"uv": [5, 11.5, 4.5, 13], "texture": "#0"} + } + } + ], + "display": { + "thirdperson_righthand": { + "translation": [0, -4.5, -0.5] + }, + "thirdperson_lefthand": { + "translation": [0, -4.5, -0.5] + }, + "firstperson_righthand": { + "translation": [-9, 0, 0] + }, + "firstperson_lefthand": { + "translation": [-9, 0, 0] + }, + "ground": { + "translation": [0, 4, 0] + }, + "gui": { + "rotation": [0, 120, 30], + "translation": [0, 1.5, 0] + }, + "head": { + "translation": [0, 14.25, 0] + } + } } \ No newline at end of file diff --git a/src/main/resources/assets/fire_protection_equipment/models/item/fire_extinguishing_bomb.json b/src/main/resources/assets/fire_protection_equipment/models/item/fire_extinguishing_bomb.json new file mode 100644 index 0000000..ace5e33 --- /dev/null +++ b/src/main/resources/assets/fire_protection_equipment/models/item/fire_extinguishing_bomb.json @@ -0,0 +1,3 @@ +{ + "parent": "fire_protection_equipment:block/fire_extinguishing_bomb" +} \ No newline at end of file diff --git a/src/main/resources/assets/fire_protection_equipment/models/item/fire_hydrant.json b/src/main/resources/assets/fire_protection_equipment/models/item/fire_hydrant.json index dac85e2..abcbc45 100644 --- a/src/main/resources/assets/fire_protection_equipment/models/item/fire_hydrant.json +++ b/src/main/resources/assets/fire_protection_equipment/models/item/fire_hydrant.json @@ -1,6 +1,6 @@ { "parent": "item/generated", "textures": { - "layer0": "fire_protection_equipment:item/fire" + "layer0": "fire_protection_equipment:item/fire_hydrant" } } \ No newline at end of file diff --git a/src/main/resources/assets/fire_protection_equipment/models/item/furnace_fire_protection_device.json b/src/main/resources/assets/fire_protection_equipment/models/item/furnace_fire_protection_device.json new file mode 100644 index 0000000..19739e7 --- /dev/null +++ b/src/main/resources/assets/fire_protection_equipment/models/item/furnace_fire_protection_device.json @@ -0,0 +1,6 @@ +{ + "parent": "item/generated", + "textures": { + "layer0": "minecraft:block/stone" + } +} \ No newline at end of file diff --git a/src/main/resources/assets/fire_protection_equipment/textures/block/fire_extinguisher.png b/src/main/resources/assets/fire_protection_equipment/textures/block/fire_extinguisher.png index 200aaff..96a7363 100644 Binary files a/src/main/resources/assets/fire_protection_equipment/textures/block/fire_extinguisher.png and b/src/main/resources/assets/fire_protection_equipment/textures/block/fire_extinguisher.png differ diff --git a/src/main/resources/assets/fire_protection_equipment/textures/block/fire_extinguishing_bomb_side.png b/src/main/resources/assets/fire_protection_equipment/textures/block/fire_extinguishing_bomb_side.png new file mode 100644 index 0000000..92c8ada Binary files /dev/null and b/src/main/resources/assets/fire_protection_equipment/textures/block/fire_extinguishing_bomb_side.png differ diff --git a/src/main/resources/assets/fire_protection_equipment/textures/item/fire_hydrant.png b/src/main/resources/assets/fire_protection_equipment/textures/item/fire_hydrant.png new file mode 100644 index 0000000..3ed0297 Binary files /dev/null and b/src/main/resources/assets/fire_protection_equipment/textures/item/fire_hydrant.png differ