Skip to content

Commit

Permalink
realistic magnet physics
Browse files Browse the repository at this point in the history
  • Loading branch information
GuyApooye committed Feb 25, 2025
1 parent 3c3f542 commit 2bc11c2
Show file tree
Hide file tree
Showing 12 changed files with 359 additions and 83 deletions.
4 changes: 2 additions & 2 deletions src/main/java/net/jcm/vsch/blocks/VSCHBlocks.java
Original file line number Diff line number Diff line change
Expand Up @@ -52,10 +52,10 @@ public class VSCHBlocks {
.strength(5f)
.noOcclusion()));

/*public static final RegistryObject<Block> MAGNET_BLOCK = registerBlock("magnet_block",
public static final RegistryObject<Block> MAGNET_BLOCK = registerBlock("magnet_block",
() -> new MagnetBlock(BlockBehaviour.Properties.copy(Blocks.IRON_BLOCK).sound(SoundType.COPPER)
.strength(5f)
.noOcclusion()));*/
.noOcclusion()));


//below is just tools used in adding the block
Expand Down
62 changes: 25 additions & 37 deletions src/main/java/net/jcm/vsch/blocks/custom/MagnetBlock.java
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,10 @@
import net.jcm.vsch.blocks.entity.template.ParticleBlockEntity;
import net.jcm.vsch.config.VSCHConfig;
import net.jcm.vsch.ship.DraggerData;
import net.jcm.vsch.ship.MagnetData;
import net.jcm.vsch.ship.ThrusterData;
import net.jcm.vsch.ship.VSCHForceInducedShips;
import net.jcm.vsch.util.LevelBlockPos;
import net.jcm.vsch.util.rot.DirectionalShape;
import net.jcm.vsch.util.rot.RotShape;
import net.jcm.vsch.util.rot.RotShapes;
Expand All @@ -23,6 +25,7 @@
import net.minecraft.world.item.context.BlockPlaceContext;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.block.Block;
import net.minecraft.world.level.block.DirectionalBlock;
import net.minecraft.world.level.block.EntityBlock;
import net.minecraft.world.level.block.RenderShape;
import net.minecraft.world.level.block.entity.BlockEntity;
Expand All @@ -32,9 +35,11 @@
import net.minecraft.world.level.block.state.StateDefinition;
import net.minecraft.world.level.block.state.properties.BlockStateProperties;
import net.minecraft.world.phys.BlockHitResult;
import org.valkyrienskies.mod.common.util.DimensionIdProvider;
import org.valkyrienskies.mod.common.util.VectorConversionsMCKt;


public class MagnetBlock extends BlockWithEntity<MagnetBlockEntity> {
public class MagnetBlock extends DirectionalBlock implements EntityBlock {

public MagnetBlock(Properties properties) {
super(properties);
Expand All @@ -60,11 +65,26 @@ public void onRemove(BlockState state, Level level, BlockPos pos, BlockState new
return;
}

// ----- Remove the thruster from the force appliers for the current level ----- //
// I guess VS does this automatically when switching a shipyards dimension?
VSCHForceInducedShips ships = VSCHForceInducedShips.get(level, pos);
if (ships != null) {
//ships.removeDragger(pos);
ships.removeMagnet(pos);
} else {
VSCHForceInducedShips.worldMagnets.remove(new LevelBlockPos(pos, level));
}
}

@Override
public void onPlace(BlockState state, Level level, BlockPos pos, BlockState oldState, boolean pMovedByPiston) {
super.onPlace(state, level, pos, oldState, pMovedByPiston);
if (!(level instanceof ServerLevel)) {
return;
}

VSCHForceInducedShips ships = VSCHForceInducedShips.get(level, pos);
if (ships != null) {
ships.addMagnet(pos, new MagnetData(VectorConversionsMCKt.toJOMLD(state.getValue(FACING).getNormal())));
} else {
VSCHForceInducedShips.worldMagnets.put(new LevelBlockPos(pos, level), new MagnetData(VectorConversionsMCKt.toJOMLD(state.getValue(FACING).getNormal())));
}
}

Expand All @@ -78,46 +98,14 @@ public BlockState getStateForPlacement(BlockPlaceContext ctx) {
.setValue(BlockStateProperties.FACING, dir);
}

/*@Override
public List<ItemStack> getDrops(BlockState state, LootContext.Builder builder) {
List<ItemStack> drops = new ArrayList<>(super.getDrops(state, builder));
int tier = state.getValue(TournamentProperties.TIER);
if (tier > 1) {
drops.add(new ItemStack(TournamentItems.UPGRADE_THRUSTER.get(), tier - 1));
}
return drops;
}*/

@SuppressWarnings("deprecation")
@Override
public void neighborChanged(BlockState state, Level level, BlockPos pos, Block block, BlockPos fromPos, boolean isMoving) {
super.neighborChanged(state, level, pos, block, fromPos, isMoving);

if (!(level instanceof ServerLevel)) return;

int signal = level.getBestNeighborSignal(pos);
VSCHForceInducedShips ships = VSCHForceInducedShips.get(level, pos);

if (ships != null) {
/*DraggerData data = ships.getDraggerAtPos(pos);
if (data != null) {
data.on = (signal > 0);
}*/
}
}

// Attach block entity
@Override
public MagnetBlockEntity newBlockEntity(BlockPos pos, BlockState state) {
return new MagnetBlockEntity(pos, state);
}

/*public static <T extends BlockEntity> BlockEntityTicker<T> getTickerHelper(Level level) {
return level.isClientSide() && !allowClient ? null : (level0, pos0, state0, blockEntity) -> ((TickableBlockEntity)blockEntity).tick();
}*/
@Override
public <T extends BlockEntity> BlockEntityTicker<T> getTicker(Level level, BlockState state, BlockEntityType<T> type) {
return level.isClientSide() ? (ParticleBlockEntity::clientTick) : ParticleBlockEntity::serverTick;
return (level0, pos, state0, be) -> ((MagnetBlockEntity) be).tick();
}
}
32 changes: 4 additions & 28 deletions src/main/java/net/jcm/vsch/blocks/entity/MagnetBlockEntity.java
Original file line number Diff line number Diff line change
@@ -1,40 +1,16 @@
package net.jcm.vsch.blocks.entity;

import net.jcm.vsch.blocks.custom.template.BlockEntityWithEntity;
import net.jcm.vsch.entity.MagnetEntity;
import net.jcm.vsch.entity.VSCHEntities;
import net.jcm.vsch.ship.VSCHForceInducedShips;
import net.minecraft.core.BlockPos;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.block.entity.BlockEntity;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.phys.Vec3;

public class MagnetBlockEntity extends BlockEntityWithEntity<MagnetEntity> {
public class MagnetBlockEntity extends BlockEntity {

public MagnetBlockEntity(BlockPos pos, BlockState state) {
super(VSCHBlockEntities.DRAG_INDUCER_BLOCK_ENTITY.get(), pos, state);
super(VSCHBlockEntities.MAGNET_BLOCK_ENTITY.get(), pos, state);
}

@Override
public void tickForce(ServerLevel level, BlockPos pos, BlockState state) {
this.spawnLinkedEntityIfNeeded();
super.tickForce(level, pos, state);
public void tick() {

// ----- Add thruster to the force appliers for the current level ----- //

int signal = level.getBestNeighborSignal(pos);
VSCHForceInducedShips ships = VSCHForceInducedShips.get(level, pos);

if (ships != null) {
/*if (ships.getDraggerAtPos(pos) == null) {
ships.addDragger(pos, new DraggerData(signal > 0));
}*/
}
}

@Override
public MagnetEntity createLinkedEntity(ServerLevel level, BlockPos pos) {
return new MagnetEntity(VSCHEntities.MAGNET_ENTITY.get(), level, pos);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,11 @@ public class VSCHBlockEntities {
() -> BlockEntityType.Builder.of(DragInducerBlockEntity::new, VSCHBlocks.DRAG_INDUCER_BLOCK.get())
.build(null));

public static final RegistryObject<BlockEntityType<MagnetBlockEntity>> MAGNET_BLOCK_ENTITY =
BLOCK_ENTITIES.register("magnet_block",
() -> BlockEntityType.Builder.of(MagnetBlockEntity::new, VSCHBlocks.MAGNET_BLOCK.get())
.build(null));

public static final RegistryObject<BlockEntityType<GravityInducerBlockEntity>> GRAVITY_INDUCER_BLOCK_ENTITY =
BLOCK_ENTITIES.register("gravity_inducer_block",
() -> BlockEntityType.Builder.of(GravityInducerBlockEntity::new, VSCHBlocks.GRAVITY_INDUCER_BLOCK.get())
Expand Down
1 change: 0 additions & 1 deletion src/main/java/net/jcm/vsch/event/AtmosphericCollision.java
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
package net.jcm.vsch.event;

import net.jcm.vsch.util.TeleportUtils;
import net.jcm.vsch.util.TeleportationHandler;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.world.level.LevelAccessor;
Expand Down
117 changes: 117 additions & 0 deletions src/main/java/net/jcm/vsch/event/PhysTick.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
package net.jcm.vsch.event;

import it.unimi.dsi.fastutil.longs.Long2ObjectMap;
import net.jcm.vsch.ship.VSCHForceInducedShips;
import net.minecraft.util.Mth;
import org.joml.Vector3d;
import org.valkyrienskies.core.api.ships.QueryableShipData;
import org.valkyrienskies.core.api.ships.ServerShip;
import org.valkyrienskies.core.impl.game.ships.PhysShipImpl;
import org.valkyrienskies.mod.common.VSGameUtilsKt;
import org.valkyrienskies.mod.common.ValkyrienSkiesMod;
import org.valkyrienskies.mod.common.util.VectorConversionsMCKt;

import java.text.NumberFormat;
import java.util.Map;

public class PhysTick {

public static final double PERMEABILITY = 0.05d;
public static final double MAX_FORCE = 100000000.0d;
public static final double MAX_LENGTH = 100.0d;


public static void apply(Map<String, Long2ObjectMap<PhysShipImpl>> dimensionToShipIdToPhysShip) {
double deltaTime = 1.0 / (VSGameUtilsKt.getVsPipeline(ValkyrienSkiesMod.getCurrentServer()).computePhysTps());

dimensionToShipIdToPhysShip.forEach((dim, idToPhysShip) -> {

QueryableShipData<ServerShip> allShips = VSGameUtilsKt.getShipObjectWorld(ValkyrienSkiesMod.getCurrentServer()).getAllShips();

idToPhysShip.forEach((id1, physShip1) -> {
ServerShip ship1 = allShips.getById(id1);

if (ship1 == null) return;

VSCHForceInducedShips attach1 = ship1.getAttachment(VSCHForceInducedShips.class);

if (attach1 == null) return;

idToPhysShip.forEach((id2, physShip2) -> {

if (physShip1.getPoseVel().getPos().sub(physShip2.getPoseVel().getPos(), new Vector3d()).lengthSquared() > MAX_LENGTH) return;

ServerShip ship2 = allShips.getById(id2);

if (ship2 == null || id1.equals(id2)) return;

VSCHForceInducedShips attach2 = ship2.getAttachment(VSCHForceInducedShips.class);

if (attach2 == null) return;

attach1.magnets.forEach((bPos1, data1) -> {

Vector3d acc1 = new Vector3d();
Vector3d acc2 = new Vector3d();

Vector3d shipPos1 = VectorConversionsMCKt.toJOMLD(bPos1).add(.5,.5,.5);

Vector3d shipPos1N = shipPos1.fma(0.45, data1.direction, new Vector3d());
Vector3d shipPos1S = shipPos1.fma(-0.45, data1.direction, new Vector3d());

Vector3d pos1N = physShip1.getTransform().getShipToWorld().transformPosition(shipPos1N, new Vector3d());
Vector3d pos1S = physShip1.getTransform().getShipToWorld().transformPosition(shipPos1S, new Vector3d());

attach2.magnets.forEach((bPos2, data2) -> {


Vector3d shipPos2 = VectorConversionsMCKt.toJOMLD(bPos2).add(.5,.5,.5);


Vector3d pos2N = shipPos2.fma(0.45, data2.direction, new Vector3d());
Vector3d pos2S = shipPos2.fma(-0.45, data2.direction, new Vector3d());

double totalForce = data1.force * data2.force * 10000;

physShip2.getTransform().getShipToWorld().transformPosition(pos2N);
physShip2.getTransform().getShipToWorld().transformPosition(pos2S);

acc1.add(calculateGilbertForce(pos1N, data1.force, pos2N, data2.force, true).mul(totalForce));
acc1.add(calculateGilbertForce(pos1N, data1.force, pos2S, data2.force, false).mul(totalForce));

acc2.add(calculateGilbertForce(pos1S, data1.force, pos2N, data2.force, false).mul(totalForce));
acc2.add(calculateGilbertForce(pos1S, data1.force, pos2S, data2.force, true).mul(totalForce));


});

if (acc1.lengthSquared() > MAX_FORCE * MAX_FORCE) acc1.normalize(MAX_FORCE);
if (acc2.lengthSquared() > MAX_FORCE * MAX_FORCE) acc2.normalize(MAX_FORCE);

physShip1.applyInvariantForceToPos(acc1, shipPos1N.sub(physShip1.getTransform().getPositionInShip(), new Vector3d()));
physShip1.applyInvariantForceToPos(acc2, shipPos1S.sub(physShip1.getTransform().getPositionInShip(), new Vector3d()));

});
});
});
});
}

private static Vector3d calculateGilbertForce(Vector3d pos1, double force1, Vector3d pos2, double force2, boolean samePole) {
Vector3d r = pos2.sub(pos1, new Vector3d());
double dist = r.length();
double part0 = PERMEABILITY * force1 * force2;
double part1 = 4 * Math.PI * dist;

double f = (part0 / part1);

if (samePole)
f = -f;

r.normalize(f);

System.out.println(r.toString(NumberFormat.getInstance()));

return r;
}
}
28 changes: 28 additions & 0 deletions src/main/java/net/jcm/vsch/mixin/VSPhysicsPipelineStageMixin.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
package net.jcm.vsch.mixin;

import it.unimi.dsi.fastutil.longs.Long2ObjectMap;
import net.jcm.vsch.event.PhysTick;
import org.joml.Vector3dc;
import org.spongepowered.asm.mixin.Final;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
import org.valkyrienskies.core.impl.game.ships.PhysShipImpl;
import org.valkyrienskies.core.impl.shadow.Ao;
import org.valkyrienskies.core.impl.shadow.Aq;

import java.util.Map;

/**@deprecated really, really sus vscore reference*/
@Deprecated
@Mixin(value = Aq.class, remap = false)
public class VSPhysicsPipelineStageMixin {
@Shadow @Final private Map<String, Long2ObjectMap<PhysShipImpl>> h;

@Inject(method = "a(Lorg/joml/Vector3dc;DZ)Lorg/valkyrienskies/core/impl/shadow/Ao;", at = @At("TAIL"))
public void physTickHook(Vector3dc par1, double par2, boolean par3, CallbackInfoReturnable<Ao> cir) {
PhysTick.apply(h);
}
}
22 changes: 22 additions & 0 deletions src/main/java/net/jcm/vsch/ship/MagnetData.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
package net.jcm.vsch.ship;

import org.joml.Vector3d;

public class MagnetData {

public volatile double force = 10.0;

public final Vector3d direction;

public MagnetData() {
direction = null;
}

public MagnetData(Vector3d direction, double force) {
this.direction = direction;
this.force = force;
}
public MagnetData(Vector3d direction) {
this.direction = direction;
}
}
Loading

0 comments on commit 2bc11c2

Please sign in to comment.