Black holes

This commit is contained in:
DBotThePony 2021-08-30 10:22:58 +07:00
parent ac7bcc0f75
commit 8fe2d8daa8
Signed by: DBot
GPG Key ID: DCC23B5715498507
7 changed files with 427 additions and 3 deletions

13
.gitignore vendored
View File

@ -100,3 +100,16 @@ forge*changelog.txt
/src/main/resources/assets/overdrive_that_matters/models/block/crate_red.json
/src/main/resources/assets/overdrive_that_matters/models/block/crate_yellow.json
/src/main/resources/assets/overdrive_that_matters/models/block/tritanium_block.json
/src/main/resources/assets/overdrive_that_matters/blockstates/black_hole.json
/src/main/resources/assets/overdrive_that_matters/models/block/black_hole.json
/src/main/resources/assets/overdrive_that_matters/models/item/black_hole.json
/src/main/resources/assets/overdrive_that_matters/models/item/carbon_fibre_block.json
/src/main/resources/assets/overdrive_that_matters/models/item/crate_black.json
/src/main/resources/assets/overdrive_that_matters/models/item/crate_blue.json
/src/main/resources/assets/overdrive_that_matters/models/item/crate_green.json
/src/main/resources/assets/overdrive_that_matters/models/item/crate_pink.json
/src/main/resources/assets/overdrive_that_matters/models/item/crate_purple.json
/src/main/resources/assets/overdrive_that_matters/models/item/crate_red.json
/src/main/resources/assets/overdrive_that_matters/models/item/crate_yellow.json
/src/main/resources/assets/overdrive_that_matters/models/item/tritanium_block.json
/src/main/resources/assets/overdrive_that_matters/models/item/tritanium_striped_block.json

View File

@ -2,6 +2,7 @@
const models = [
'android_station',
'battery_bank',
'black_hole',
['matter_scanner', 'matter_scanner_working'],
'pattern_storage',
['matter_replicator', 'matter_replicator_working'],
@ -16,12 +17,143 @@ const root = _root + 'models/block/'
const time = Date.now()
process.stdout.write('Regenerating data files\n')
// "модель" горизонта событий / черной дыры
{
const elements = []
// сфера
const layers = 32
const radius = 16
const checked = new Array(Math.pow(layers, 3))
// создание + слияние вдоль Y
for (let y = -layers / 2; y < layers / 2; y++) {
for (let x = -layers / 2; x < layers / 2; x++) {
for (let z = -layers / 2; z < layers / 2; z++) {
const dist1 = Math.sqrt(x * x + y * y + z * z)
if (dist1 <= radius) {
const index1 = x + layers / 2 + (z + layers / 2) * layers + (y + layers / 2) * layers * layers
if (!checked[index1]) {
let height = 0
let index
for (let y2 = 0; y2 < layers; y2++) {
const dist = Math.sqrt(x * x + (y + y2) * (y + y2) + z * z)
const index2 = x + layers / 2 + (z + layers / 2) * layers + (y + y2 + layers / 2) * layers * layers
if (dist <= radius && !checked[index2]) {
height = y2
index = index2
} else {
break
}
}
if (height > 0) {
checked[index] = {
"from": [4 + (x + layers / 2) / layers * 8, 4 + (y + layers / 2) / layers * 8, 4 + (z + layers / 2) / layers * 8],
"to": [4 + (x + layers / 2 + 1) / layers * 8, 4 + (y + layers / 2 + height) / layers * 8, 4 + (z + layers / 2 + 1) / layers * 8],
"faces": {
"down": { "texture": "#black_hole" },
"up": { "texture": "#black_hole" },
"north": { "texture": "#black_hole" },
"south": { "texture": "#black_hole" },
"west": { "texture": "#black_hole" },
"east": { "texture": "#black_hole" }
}
}
elements.push(checked[index])
}
}
}
}
}
}
// слияние вдоль X
for (let y = -layers / 2; y < layers / 2; y++) {
for (let z = -layers / 2; z < layers / 2; z++) {
let last_element = null
for (let x = -layers / 2; x < layers / 2; x++) {
const index = x + layers / 2 + (z + layers / 2) * layers + (y + layers / 2) * layers * layers
if (checked[index]) {
if (last_element) {
const from1 = checked[index].from
const from2 = last_element.from
if (from1[1] == from2[1] && from1[2] == from2[2]) {
last_element.to[0] = checked[index].to[0]
checked[index] = last_element
} else {
last_element = checked[index]
}
} else {
last_element = checked[index]
}
}
}
}
}
const merged_z = []
// слияние вдоль Z
for (let y = -layers / 2; y < layers / 2; y++) {
for (let x = -layers / 2; x < layers / 2; x++) {
let last_element = null
for (let z = -layers / 2; z < layers / 2; z++) {
const index = x + layers / 2 + (z + layers / 2) * layers + (y + layers / 2) * layers * layers
if (checked[index]) {
if (last_element) {
const from1 = checked[index].from
const from2 = last_element.from
if (from1[0] == from2[0] && from1[1] == from2[1]) {
last_element.to[2] = checked[index].to[2]
checked[index] = last_element
} else {
if (!merged_z.includes(last_element)) {
merged_z.push(last_element)
}
last_element = checked[index]
}
} else {
last_element = checked[index]
}
}
}
if (last_element && !merged_z.includes(last_element)) {
merged_z.push(last_element)
}
}
}
fs.writeFileSync(root + 'black_hole.json', JSON.stringify({
"parent": "block/block",
"textures": {
"black_hole": "overdrive_that_matters:block/black_hole"
},
"elements": merged_z
}, null, '\t'))
}
const handle = fs.openSync('./src/main/java/ru/dbotthepony/mc/otm/shapes/BlockShapes.java', 'w')
fs.writeSync(handle, 'package ru.dbotthepony.mc.otm.shapes;\n\n\n')
fs.writeSync(handle, `// This file is regenerated on each gradle run. Do not edit it!\n`)
fs.writeSync(handle, 'public class BlockShapes {\n')
// модели блоков
for (const _model of models) {
let model, path
@ -201,6 +333,8 @@ const facings = [
'crate_black',
'crate_pink',
'crate_purple',
'black_hole',
]
const blocks2 = [
@ -224,6 +358,10 @@ const facings = [
}
}
}, null, '\t'))
fs.writeFileSync(_root + 'models/item/' + name + '.json', JSON.stringify({
"parent": "overdrive_that_matters:block/" + name
}, null, '\t'))
}
for (const name of blocks2) {

View File

@ -40,12 +40,14 @@ import ru.dbotthepony.mc.otm.screen.*;
import java.math.BigDecimal;
public class Registry {
public static final DamageSource DAMAGE_BECOME_ANDROID = new DamageSource("otmBecomeAndroid");
public static final DamageSource DAMAGE_BECOME_HUMANE = new DamageSource("otmBecomeHumane");
public static final DamageSource DAMAGE_BECOME_ANDROID = new DamageSource("otm_become_android");
public static final DamageSource DAMAGE_BECOME_HUMANE = new DamageSource("otm_become_humane");
public static final DamageSource DAMAGE_EVENT_HORIZON = new DamageSource("otm_event_horizon");
static {
DAMAGE_BECOME_ANDROID.bypassArmor().bypassInvul().bypassMagic();
DAMAGE_BECOME_HUMANE.bypassArmor().bypassInvul().bypassMagic();
DAMAGE_EVENT_HORIZON.bypassMagic().bypassArmor();
}
private static ForgeRegistry<AndroidFeatureType<?>> ANDROID_FEATURES;
@ -109,6 +111,8 @@ public class Registry {
public static final ResourceLocation MATTER_BOTTLER = new ResourceLocation(OverdriveThatMatters.MOD_ID, "matter_bottler");
public static final ResourceLocation DRIVE_VIEWER = new ResourceLocation(OverdriveThatMatters.MOD_ID, "drive_viewer");
public static final ResourceLocation BLACK_HOLE = new ResourceLocation(OverdriveThatMatters.MOD_ID, "black_hole");
// building blocks
public static final ResourceLocation TRITANIUM_BLOCK = new ResourceLocation(OverdriveThatMatters.MOD_ID, "tritanium_block");
public static final ResourceLocation TRITANIUM_STRIPED_BLOCK = new ResourceLocation(OverdriveThatMatters.MOD_ID, "tritanium_striped_block");
@ -204,6 +208,8 @@ public class Registry {
public static final Block MATTER_BOTTLER = new BlockMatterBottler();
public static final Block DRIVE_VIEWER = new BlockDriveViewer();
public static final Block BLACK_HOLE = new BlockBlackHole();
public static final Block[] CRATES = new Block[Registry.CRATES.length];
public static final Block TRITANIUM_BLOCK = new Block(
@ -251,6 +257,7 @@ public class Registry {
MATTER_REPLICATOR.setRegistryName(Names.MATTER_REPLICATOR);
MATTER_BOTTLER.setRegistryName(Names.MATTER_BOTTLER);
DRIVE_VIEWER.setRegistryName(Names.DRIVE_VIEWER);
BLACK_HOLE.setRegistryName(Names.BLACK_HOLE);
TRITANIUM_BLOCK.setRegistryName(Names.TRITANIUM_BLOCK);
TRITANIUM_STRIPED_BLOCK.setRegistryName(Names.TRITANIUM_STRIPED_BLOCK);
@ -273,6 +280,7 @@ public class Registry {
event.getRegistry().register(TRITANIUM_BLOCK);
event.getRegistry().register(TRITANIUM_STRIPED_BLOCK);
event.getRegistry().register(CARBON_FIBRE_BLOCK);
event.getRegistry().register(BLACK_HOLE);
for (var crate : CRATES) {
event.getRegistry().register(crate);
@ -295,6 +303,8 @@ public class Registry {
public static final Item MATTER_BOTTLER = new BlockItem(Blocks.MATTER_BOTTLER, new Item.Properties().stacksTo(64).tab(OverdriveThatMatters.CREATIVE_TAB));
public static final Item DRIVE_VIEWER = new BlockItem(Blocks.DRIVE_VIEWER, new Item.Properties().stacksTo(64).tab(OverdriveThatMatters.CREATIVE_TAB));
public static final Item BLACK_HOLE = new BlockItem(Blocks.BLACK_HOLE, new Item.Properties().stacksTo(64).tab(OverdriveThatMatters.CREATIVE_TAB));
public static final ItemPill PILL_ANDROID = new ItemPill(ItemPill.PillType.BECOME_ANDROID);
public static final ItemPill PILL_HUMANE = new ItemPill(ItemPill.PillType.BECOME_HUMANE);
@ -339,6 +349,7 @@ public class Registry {
MATTER_REPLICATOR.setRegistryName(Names.MATTER_REPLICATOR);
MATTER_BOTTLER.setRegistryName(Names.MATTER_BOTTLER);
DRIVE_VIEWER.setRegistryName(Names.DRIVE_VIEWER);
BLACK_HOLE.setRegistryName(Names.BLACK_HOLE);
PILL_ANDROID.setRegistryName(Names.PILL_ANDROID);
PILL_HUMANE.setRegistryName(Names.PILL_HUMANE);
@ -377,6 +388,7 @@ public class Registry {
event.getRegistry().register(MATTER_REPLICATOR);
event.getRegistry().register(MATTER_BOTTLER);
event.getRegistry().register(DRIVE_VIEWER);
event.getRegistry().register(BLACK_HOLE);
event.getRegistry().register(PILL_ANDROID);
event.getRegistry().register(PILL_HUMANE);
@ -421,6 +433,7 @@ public class Registry {
public static final BlockEntityType<BlockEntityMatterReplicator> MATTER_REPLICATOR = BlockEntityType.Builder.of(BlockEntityMatterReplicator::new, Blocks.MATTER_REPLICATOR).build(null);
public static final BlockEntityType<BlockEntityMatterBottler> MATTER_BOTTLER = BlockEntityType.Builder.of(BlockEntityMatterBottler::new, Blocks.MATTER_BOTTLER).build(null);
public static final BlockEntityType<BlockEntityDriveViewer> DRIVE_VIEWER = BlockEntityType.Builder.of(BlockEntityDriveViewer::new, Blocks.DRIVE_VIEWER).build(null);
public static final BlockEntityType<BlockEntityBlackHole> BLACK_HOLE = BlockEntityType.Builder.of(BlockEntityBlackHole::new, Blocks.BLACK_HOLE).build(null);
static {
ANDROID_STATION.setRegistryName(Names.ANDROID_STATION);
@ -434,6 +447,7 @@ public class Registry {
MATTER_REPLICATOR.setRegistryName(Names.MATTER_REPLICATOR);
MATTER_BOTTLER.setRegistryName(Names.MATTER_BOTTLER);
DRIVE_VIEWER.setRegistryName(Names.DRIVE_VIEWER);
BLACK_HOLE.setRegistryName(Names.BLACK_HOLE);
}
@SubscribeEvent
@ -449,6 +463,7 @@ public class Registry {
event.getRegistry().register(MATTER_REPLICATOR);
event.getRegistry().register(MATTER_BOTTLER);
event.getRegistry().register(DRIVE_VIEWER);
event.getRegistry().register(BLACK_HOLE);
// OverdriveThatMatters.LOGGER.info("Registered block entities");
}

View File

@ -1,6 +1,50 @@
package ru.dbotthepony.mc.otm.block;
import net.minecraft.core.BlockPos;
import net.minecraft.world.level.BlockGetter;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.block.Block;
import net.minecraft.world.level.block.EntityBlock;
import net.minecraft.world.level.block.entity.BlockEntity;
import net.minecraft.world.level.block.entity.BlockEntityTicker;
import net.minecraft.world.level.block.entity.BlockEntityType;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.level.material.Material;
import net.minecraft.world.level.material.MaterialColor;
import net.minecraft.world.phys.shapes.CollisionContext;
import net.minecraft.world.phys.shapes.VoxelShape;
import ru.dbotthepony.mc.otm.Registry;
import ru.dbotthepony.mc.otm.block.entity.BlockEntityBlackHole;
import ru.dbotthepony.mc.otm.shapes.BlockShapes;
public class BlockBlackHole extends Block {
import javax.annotation.Nullable;
public class BlockBlackHole extends Block implements EntityBlock {
public BlockBlackHole() {
super(Properties.of(
new Material.Builder(MaterialColor.COLOR_BLACK).noCollider().nonSolid().build()
).strength(-1, 7200000.0F));
}
public static final VoxelShape SHAPE = BlockShapes.BLACK_HOLE.computeShape();
@Override
public VoxelShape getShape(BlockState p_60555_, BlockGetter p_60556_, BlockPos p_60557_, CollisionContext p_60558_) {
return SHAPE;
}
@Nullable
@Override
public BlockEntity newBlockEntity(BlockPos blockPos, BlockState blockState) {
return new BlockEntityBlackHole(blockPos, blockState);
}
@Nullable
@Override
public <T extends BlockEntity> BlockEntityTicker<T> getTicker(Level p_153212_, BlockState p_153213_, BlockEntityType<T> p_153214_) {
if (p_153214_ != Registry.BlockEntities.BLACK_HOLE)
return null;
return p_153212_.isClientSide ? BlockEntityBlackHole::clientTicker : BlockEntityBlackHole::ticker;
}
}

View File

@ -0,0 +1,205 @@
package ru.dbotthepony.mc.otm.block.entity;
import net.minecraft.client.Minecraft;
import net.minecraft.core.BlockPos;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.nbt.StringTag;
import net.minecraft.network.Connection;
import net.minecraft.network.protocol.PacketFlow;
import net.minecraft.network.protocol.game.ClientboundBlockEntityDataPacket;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.entity.LivingEntity;
import net.minecraft.world.entity.item.ItemEntity;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.block.Block;
import net.minecraft.world.level.block.entity.BlockEntity;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.level.levelgen.structure.BoundingBox;
import net.minecraft.world.phys.AABB;
import net.minecraft.world.phys.Vec3;
import ru.dbotthepony.mc.otm.Registry;
import ru.dbotthepony.mc.otm.capability.MatteryCapability;
import ru.dbotthepony.mc.otm.matter.MatterRegistry;
import javax.annotation.Nullable;
import java.math.BigDecimal;
public class BlockEntityBlackHole extends BlockEntity {
public BlockEntityBlackHole(BlockPos p_155229_, BlockState p_155230_) {
super(Registry.BlockEntities.BLACK_HOLE, p_155229_, p_155230_);
setMass(mass);
}
public static final BigDecimal NORMAL_MASS = new BigDecimal(10_000);
private BigDecimal mass = NORMAL_MASS;
private double gravitation_strength = 1;
private boolean suppress_updates = true;
public void collapse() {
}
public void addMass(BigDecimal mass) {
setMass(this.mass.add(mass));
}
public void setMass(BigDecimal mass) {
if (mass.compareTo(BigDecimal.ZERO) <= 0) {
collapse();
return;
}
this.mass = mass;
setChanged();
gravitation_strength = mass.divide(NORMAL_MASS, MatteryCapability.ROUND_RULES).doubleValue();
if (level != null && !level.isClientSide && !suppress_updates)
level.sendBlockUpdated(getBlockPos(), getBlockState(), getBlockState(), Block.UPDATE_CLIENTS);
affected_bounds = new BoundingBox(
(int) (-30 * gravitation_strength),
(int) (-30 * gravitation_strength),
(int) (-30 * gravitation_strength),
(int) (30 * gravitation_strength),
(int) (30 * gravitation_strength),
(int) (30 * gravitation_strength)
).move(getBlockPos());
affected_bounds_aabb = AABB.of(affected_bounds);
}
// shared functions
public CompoundTag writeBlackHoleData(CompoundTag tag) {
tag.putString("mass", mass.toString());
return tag;
}
public void readBlackHoleData(CompoundTag tag) {
if (tag.get("mass") instanceof StringTag str)
setMass(new BigDecimal(str.getAsString()));
}
// disk io
@Override
public CompoundTag save(CompoundTag tag) {
writeBlackHoleData(tag);
return super.save(tag);
}
@Override
public void load(CompoundTag tag) {
super.load(tag);
readBlackHoleData(tag);
}
// received either by game engine (from getUpdateTag on ClientLevelPacket)
// or by onDataPacket
@Override
public void handleUpdateTag(CompoundTag tag) {
super.handleUpdateTag(tag);
readBlackHoleData(tag);
}
// called by game engine for ClientLevelPacket
@Override
public CompoundTag getUpdateTag() {
return writeBlackHoleData(super.getUpdateTag());
}
// called by game engine on block updsates
@Nullable
@Override
public ClientboundBlockEntityDataPacket getUpdatePacket() {
return new ClientboundBlockEntityDataPacket(getBlockPos(), 0, writeBlackHoleData(new CompoundTag()));
}
// called by game engine by forge patches when ClientboundBlockEntityDataPacket is received
@Override
public void onDataPacket(Connection net, ClientboundBlockEntityDataPacket pkt) {
super.onDataPacket(net, pkt);
if (net.getReceiving() == PacketFlow.CLIENTBOUND) {
handleUpdateTag(pkt.getTag());
}
}
private BoundingBox affected_bounds;
private AABB affected_bounds_aabb;
public BoundingBox affectedBounds() {
return affected_bounds;
}
public AABB affectedBoundsAABB() {
return affected_bounds_aabb;
}
private void setDeltaMovement(Entity living, Vec3 center, double distance) {
//final double mult = Math.min(2, (30 * this.gravitation_strength) / Math.max(1, Math.pow(distance, 2)));
final double mult = Math.pow(1 - distance / (30 * this.gravitation_strength), 2) * this.gravitation_strength / 8;
final var delta = living.position().vectorTo(center).normalize();
living.setDeltaMovement(living.getDeltaMovement().add(delta.multiply(mult, mult, mult)));
}
public static <T extends BlockEntity> void clientTicker(Level level, BlockPos blockPos, BlockState blockState, T t) {
if (t instanceof BlockEntityBlackHole tile) {
var ply = Minecraft.getInstance().player;
final var center = Vec3.atCenterOf(tile.getBlockPos());
if (!ply.getAbilities().mayfly) {
final double distance = ply.position().distanceTo(center);
tile.setDeltaMovement(ply, center, distance);
}
for (var item : tile.level.getEntitiesOfClass(ItemEntity.class, tile.affected_bounds_aabb)) {
final double distance = item.position().distanceTo(center);
tile.setDeltaMovement(item, center, distance);
if (distance < tile.gravitation_strength * 2) {
if (item.hurt(Registry.DAMAGE_EVENT_HORIZON, (float) (tile.gravitation_strength / distance)) && item.isRemoved()) {
var mass = MatterRegistry.getMatterValue(item.getItem());
if (mass.compareTo(BigDecimal.ZERO) > 0)
tile.addMass(mass);
}
}
}
}
}
public static <T extends BlockEntity> void ticker(Level level, BlockPos blockPos, BlockState blockState, T t) {
if (t instanceof BlockEntityBlackHole tile) {
tile.suppress_updates = false;
final var center = Vec3.atCenterOf(tile.getBlockPos());
for (var living : tile.level.getEntitiesOfClass(LivingEntity.class, tile.affected_bounds_aabb)) {
final double distance = living.position().distanceTo(center);
if (!(living instanceof Player ply) || !ply.getAbilities().mayfly) {
tile.setDeltaMovement(living, center, distance);
}
if (distance < tile.gravitation_strength * 2) {
living.hurt(Registry.DAMAGE_EVENT_HORIZON, (float) (tile.gravitation_strength / distance));
}
}
for (var item : tile.level.getEntitiesOfClass(ItemEntity.class, tile.affected_bounds_aabb)) {
final double distance = item.position().distanceTo(center);
tile.setDeltaMovement(item, center, distance);
if (distance < tile.gravitation_strength * 2) {
if (item.hurt(Registry.DAMAGE_EVENT_HORIZON, (float) (tile.gravitation_strength / distance)) && item.isRemoved()) {
var mass = MatterRegistry.getMatterValue(item.getItem());
if (mass.compareTo(BigDecimal.ZERO) > 0)
tile.addMass(mass);
}
}
}
}
}
}

View File

@ -111,6 +111,14 @@
"otm.suffix.zepto": "%s z%s",
"otm.suffix.yocto": "%s y%s",
"death.attack.otm_become_android": "%1$s lost their humanity",
"death.attack.otm_become_humane": "%1$s gained their humanity",
"death.attack.otm_event_horizon": "%1$s never crossed event horizon",
"death.attack.otm_become_android.player": "%1$s lost their humanity whilst %2$s tried to reason with them",
"death.attack.otm_become_humane.player": "%1$s gained their humanity whilst %2$s tried to reason with them",
"death.attack.otm_event_horizon.player": "%1$s tried to cross event horizon whilst trying to escape %2$s",
"block.overdrive_that_matters.android_station": "Android station",
"block.overdrive_that_matters.battery_bank": "Battery bank",
"block.overdrive_that_matters.matter_decomposer": "Matter decomposer",
@ -122,6 +130,7 @@
"block.overdrive_that_matters.matter_replicator": "Matter replicator",
"block.overdrive_that_matters.matter_bottler": "Matter bottler",
"block.overdrive_that_matters.drive_viewer": "Drive viewer",
"block.overdrive_that_matters.black_hole": "Miniature Event Horizon",
"otm.container.matter_panel.number_input": "Input replication task count",

Binary file not shown.

After

Width:  |  Height:  |  Size: 141 B