@@ -50,11 +50,9 @@ namespace GamecraftModdingAPI | |||
/// <param name="autoWire">Whether the block should be auto-wired (if functional)</param> | |||
/// <param name="player">The player who placed the block</param> | |||
/// <returns>The placed block or null if failed</returns> | |||
public static Block PlaceNew(BlockIDs block, float3 position, float3 rotation = default, | |||
BlockColors color = BlockColors.Default, BlockMaterial material = BlockMaterial.Default, | |||
int uscale = 1, float3 scale = default, bool isFlipped = false, bool autoWire = false, Player player = null) | |||
public static Block PlaceNew(BlockIDs block, float3 position, bool autoWire = false, Player player = null) | |||
{ | |||
return PlaceNew<Block>(block, position, rotation, color, material, uscale, scale, isFlipped, autoWire, player); | |||
return PlaceNew<Block>(block, position, autoWire, player); | |||
} | |||
/// <summary> | |||
@@ -73,15 +71,13 @@ namespace GamecraftModdingAPI | |||
/// <param name="autoWire">Whether the block should be auto-wired (if functional)</param> | |||
/// <param name="player">The player who placed the block</param> | |||
/// <returns>The placed block or null if failed</returns> | |||
public static T PlaceNew<T>(BlockIDs block, float3 position, | |||
float3 rotation = default, BlockColor? color = null, BlockMaterial material = BlockMaterial.Default, | |||
int uscale = 1, float3 scale = default, bool isFlipped = false, bool autoWire = false, Player player = null) | |||
public static T PlaceNew<T>(BlockIDs block, float3 position, bool autoWire = false, Player player = null) | |||
where T : Block | |||
{ | |||
if (PlacementEngine.IsInGame && GameState.IsBuildMode()) | |||
{ | |||
var egid = PlacementEngine.PlaceBlock(block, color ?? BlockColors.Default, material, | |||
position, uscale, scale, player, rotation, isFlipped, autoWire, out var initializer); | |||
var initializer = PlacementEngine.PlaceBlock(block, position, player, autoWire); | |||
var egid = initializer.EGID; | |||
var bl = New<T>(egid.entityID, egid.groupID); | |||
bl.InitData.Group = BlockEngine.InitGroup(initializer); | |||
Placed += bl.OnPlacedInit; | |||
@@ -232,6 +228,23 @@ namespace GamecraftModdingAPI | |||
Id = BlockEngine.FindBlockEGID(id) ?? throw new BlockTypeException("Could not find the appropriate group for the block. The block probably doesn't exist or hasn't been submitted."); | |||
} | |||
/// <summary> | |||
/// Places a new block in the world. | |||
/// </summary> | |||
/// <param name="type">The block's type</param> | |||
/// <param name="position">The block's position (a block is 0.2 wide in terms of position)</param> | |||
/// <param name="autoWire">Whether the block should be auto-wired (if functional)</param> | |||
/// <param name="player">The player who placed the block</param> | |||
public Block(BlockIDs type, float3 position, bool autoWire = false, Player player = null) | |||
{ | |||
if (!PlacementEngine.IsInGame || !GameState.IsBuildMode()) | |||
throw new BlockException("Blocks can only be placed in build mode."); | |||
var initializer = PlacementEngine.PlaceBlock(type, position, player, autoWire); | |||
Id = initializer.EGID; | |||
InitData.Group = BlockEngine.InitGroup(initializer); | |||
Placed += OnPlacedInit; | |||
} | |||
public EGID Id { get; } | |||
internal BlockEngine.BlockInitData InitData; | |||
@@ -277,6 +290,10 @@ namespace GamecraftModdingAPI | |||
get => BlockEngine.GetBlockInfo(this, (ScalingEntityStruct st) => st.scale); | |||
set | |||
{ | |||
int uscale = UniformScale; | |||
if (value.x < 4e-5) value.x = uscale; | |||
if (value.y < 4e-5) value.y = uscale; | |||
if (value.z < 4e-5) value.z = uscale; | |||
BlockEngine.SetBlockInfo(this, (ref ScalingEntityStruct st, float3 val) => st.scale = val, value); | |||
if (!Exists) return; //UpdateCollision needs the block to exist | |||
ScalingEngine.UpdateCollision(Id); | |||
@@ -293,6 +310,7 @@ namespace GamecraftModdingAPI | |||
get => BlockEngine.GetBlockInfo(this, (UniformBlockScaleEntityStruct st) => st.scaleFactor); | |||
set | |||
{ | |||
if (value < 1) value = 1; | |||
BlockEngine.SetBlockInfo(this, (ref UniformBlockScaleEntityStruct st, int val) => st.scaleFactor = val, | |||
value); | |||
Scale = new float3(value, value, value); | |||
@@ -300,7 +318,7 @@ namespace GamecraftModdingAPI | |||
} | |||
/** | |||
* Whether the block is fipped. | |||
* Whether the block is flipped. | |||
*/ | |||
public bool Flipped | |||
{ | |||
@@ -342,7 +360,7 @@ namespace GamecraftModdingAPI | |||
set | |||
{ | |||
BlockEngine.SetBlockInfo(this, (ref ColourParameterEntityStruct color, BlockColor val) => | |||
{ | |||
{ //TODO: Check if setting to 255 works | |||
color.indexInPalette = val.Index; | |||
color.hasNetworkChange = true; | |||
color.paletteColour = BlockEngine.ConvertBlockColor(color.indexInPalette); | |||
@@ -366,9 +384,12 @@ namespace GamecraftModdingAPI | |||
} | |||
} | |||
/** | |||
* The block's material. | |||
*/ | |||
public BlockMaterial Material | |||
{ | |||
get => BlockEngine.GetBlockInfo(this, (CubeMaterialStruct cmst) => (BlockMaterial) cmst.materialId); | |||
get => BlockEngine.GetBlockInfo(this, (CubeMaterialStruct cmst) => (BlockMaterial) cmst.materialId, BlockMaterial.Default); | |||
set => BlockEngine.SetBlockInfo(this, | |||
(ref CubeMaterialStruct cmst, BlockMaterial val) => cmst.materialId = (byte) val, value); | |||
} | |||
@@ -460,7 +481,12 @@ namespace GamecraftModdingAPI | |||
/// <returns></returns> | |||
public T Copy<T>() where T : Block | |||
{ | |||
var block = PlaceNew<T>(Type, Position, Rotation, Color, Material, UniformScale, Scale); | |||
var block = PlaceNew<T>(Type, Position); | |||
block.Rotation = Rotation; | |||
block.Color = Color; | |||
block.Material = Material; | |||
block.UniformScale = UniformScale; | |||
block.Scale = Scale; | |||
block.copiedFrom = Id; | |||
return block; | |||
} | |||
@@ -41,64 +41,27 @@ namespace GamecraftModdingAPI.Blocks | |||
public EntitiesDB entitiesDB { get; set; } | |||
private static BlockEntityFactory _blockEntityFactory; //Injected from PlaceSingleBlockEngine | |||
public EGID PlaceBlock(BlockIDs block, BlockColor color, BlockMaterial materialId, float3 position, int uscale, | |||
float3 scale, Player player, float3 rotation, bool isFlipped, bool autoWire, out EntityInitializer initializer) | |||
public EntityInitializer PlaceBlock(BlockIDs block, float3 position, Player player, bool autoWire) | |||
{ //It appears that only the non-uniform scale has any visible effect, but if that's not given here it will be set to the uniform one | |||
if (color.Darkness > 9) | |||
throw new Exception("That is too dark. Make sure to use 0-9 as darkness. (0 is default.)"); | |||
initializer = BuildBlock((ushort) block, color.Index, (byte) materialId, position, uscale, scale, rotation, | |||
isFlipped, autoWire, (player ?? new Player(PlayerType.Local)).Id); | |||
return initializer.EGID; | |||
return BuildBlock((ushort) block, position, autoWire, (player ?? Player.LocalPlayer).Id); | |||
} | |||
private EntityInitializer BuildBlock(ushort block, byte color, byte materialId, float3 position, int uscale, float3 scale, float3 rot, bool isFlipped, bool autoWire, uint playerId) | |||
private EntityInitializer BuildBlock(ushort block, float3 position, bool autoWire, uint playerId) | |||
{ | |||
if (_blockEntityFactory == null) | |||
throw new BlockException("The factory is null."); | |||
if (uscale < 1) | |||
throw new BlockException("Scale needs to be at least 1"); | |||
if (scale.x < 4e-5) scale.x = uscale; | |||
if (scale.y < 4e-5) scale.y = uscale; | |||
if (scale.z < 4e-5) scale.z = uscale; | |||
uint resourceId = (uint) PrefabsID.GenerateResourceID(0, block); | |||
if (!PrefabsID.PrefabIDByResourceIDMap.ContainsKey(resourceId)) | |||
throw new BlockException("Block with ID " + block + " not found!"); | |||
//RobocraftX.CR.MachineEditing.PlaceSingleBlockEngine | |||
ScalingEntityStruct scaling = new ScalingEntityStruct {scale = scale * (isFlipped ? -1 : 1)}; | |||
Quaternion rotQ = Quaternion.Euler(rot); | |||
RotationEntityStruct rotation = new RotationEntityStruct {rotation = rotQ}; | |||
GridRotationStruct gridRotation = new GridRotationStruct | |||
{position = position, rotation = rotQ}; | |||
DBEntityStruct dbEntity = new DBEntityStruct {DBID = block}; | |||
BlockPlacementScaleEntityStruct placementScale = new BlockPlacementScaleEntityStruct | |||
{ | |||
blockPlacementHeight = uscale, blockPlacementWidth = uscale, desiredScaleFactor = uscale | |||
}; | |||
EntityInitializer structInitializer = _blockEntityFactory.Build(CommonExclusiveGroups.nextBlockEntityID, block); //The ghost block index is only used for triggers | |||
if (color != byte.MaxValue) | |||
structInitializer.Init(new ColourParameterEntityStruct | |||
{ | |||
indexInPalette = color, | |||
hasNetworkChange = true | |||
}); | |||
if (materialId != byte.MaxValue) | |||
structInitializer.Init(new CubeMaterialStruct | |||
{ | |||
materialId = materialId | |||
}); | |||
uint prefabId = PrefabsID.GetOrCreatePrefabID(block, materialId, 0, isFlipped); | |||
uint prefabId = PrefabsID.GetOrCreatePrefabID(block, (byte) BlockMaterial.SteelBodywork, 0, false); | |||
structInitializer.Init(new GFXPrefabEntityStructGPUI(prefabId)); | |||
structInitializer.Init(new PhysicsPrefabEntityStruct(prefabId)); | |||
structInitializer.Init(dbEntity); | |||
structInitializer.Init(new PositionEntityStruct {position = position}); | |||
structInitializer.Init(rotation); | |||
structInitializer.Init(scaling); | |||
structInitializer.Init(gridRotation); | |||
structInitializer.Init(new UniformBlockScaleEntityStruct | |||
{ | |||
scaleFactor = placementScale.desiredScaleFactor | |||
}); | |||
structInitializer.Init(new BlockPlacementInfoStruct() | |||
{ | |||
loadedFromDisk = false, | |||
@@ -106,20 +69,19 @@ namespace GamecraftModdingAPI.Blocks | |||
triggerAutoWiring = autoWire && structInitializer.Has<BlockPortsStruct>() | |||
}); | |||
/*structInitializer.Init(new CollisionFilterOverride | |||
foreach (var group in CharacterExclusiveGroups.AllCharacters) | |||
{ | |||
belongsTo = 32U, | |||
collidesWith = 239532U | |||
});*/ | |||
EGID playerEGID = new EGID(playerId, CharacterExclusiveGroups.OnFootGroup); | |||
ref PickedBlockExtraDataStruct pickedBlock = ref entitiesDB.QueryEntity<PickedBlockExtraDataStruct>(playerEGID); | |||
pickedBlock.placedBlockEntityID = structInitializer.EGID; | |||
pickedBlock.placedBlockWasAPickedBlock = false; | |||
EGID playerEGID = new EGID(playerId, group); | |||
if (!entitiesDB.TryQueryEntitiesAndIndex<PickedBlockExtraDataStruct>(playerEGID, out uint index, | |||
out var array)) continue; | |||
ref PickedBlockExtraDataStruct pickedBlock = ref array[index]; | |||
pickedBlock.placedBlockEntityID = structInitializer.EGID; | |||
pickedBlock.placedBlockWasAPickedBlock = false; | |||
} | |||
return structInitializer; | |||
} | |||
public string Name { get; } = "GamecraftModdingAPIPlacementGameEngine"; | |||
public string Name => "GamecraftModdingAPIPlacementGameEngine"; | |||
public bool isRemovable => false; | |||
@@ -294,14 +294,13 @@ namespace GamecraftModdingAPI.Tests | |||
.Action((float x, float y, float z) => | |||
{ | |||
var pos = new float3(x, y, z); | |||
var group = BlockGroup.Create(Block.PlaceNew(BlockIDs.Cube, pos, | |||
color: BlockColors.Aqua)); | |||
Block.PlaceNew(BlockIDs.Cube, pos += new float3(1, 0, 0), color: BlockColors.Blue) | |||
.BlockGroup = group; | |||
Block.PlaceNew(BlockIDs.Cube, pos += new float3(1, 0, 0), color: BlockColors.Green) | |||
.BlockGroup = group; | |||
Block.PlaceNew(BlockIDs.Cube, pos += new float3(1, 0, 0), color: BlockColors.Lime) | |||
.BlockGroup = group; | |||
var group = BlockGroup.Create(new Block(BlockIDs.Cube, pos) {Color = BlockColors.Aqua}); | |||
new Block(BlockIDs.Cube, pos += new float3(1, 0, 0)) | |||
{Color = BlockColors.Blue, BlockGroup = group}; | |||
new Block(BlockIDs.Cube, pos += new float3(1, 0, 0)) | |||
{Color = BlockColors.Green, BlockGroup = group}; | |||
new Block(BlockIDs.Cube, pos + new float3(1, 0, 0)) | |||
{Color = BlockColors.Lime, BlockGroup = group}; | |||
}).Build(); | |||
CommandBuilder.Builder("placeCustomBlock", "Places a custom block, needs a custom catalog and assets.") | |||