@@ -14,6 +14,7 @@ namespace GamecraftModdingAPI | |||
{ | |||
/// <summary> | |||
/// A single (perhaps scaled) block. Properties may return default values if the block is removed and then setting them is ignored. | |||
/// For specific block type operations, use the specialised block classes in the GamecraftModdingAPI.Blocks namespace. | |||
/// </summary> | |||
public class Block | |||
{ | |||
@@ -81,7 +82,7 @@ namespace GamecraftModdingAPI | |||
DeterministicStepCompositionRootPatch.SubmitEntitiesNow(); | |||
} | |||
public EGID Id { get; } | |||
public EGID Id { get; protected set; } | |||
/// <summary> | |||
/// The block's current position or zero if the block no longer exists. | |||
@@ -213,6 +214,13 @@ namespace GamecraftModdingAPI | |||
GameEngineManager.AddGameEngine(BlockEngine); | |||
} | |||
/// <summary> | |||
/// Convert the block to a specialised block class. | |||
/// </summary> | |||
/// <returns>The block.</returns> | |||
/// <param name="sameTick">Force an entity sync when <c>true</c>. | |||
/// Only set this to <c>false</c> when the block was not placed the same tick this was called.</param> | |||
/// <typeparam name="T">The specialised block type.</typeparam> | |||
public T Specialise<T>(bool sameTick = true) where T : Block | |||
{ | |||
// What have I gotten myself into? | |||
@@ -0,0 +1,132 @@ | |||
using System; | |||
using RobocraftX.Blocks; | |||
using Gamecraft.CharacterVulnerability; | |||
using Svelto.ECS; | |||
using Unity.Mathematics; | |||
using GamecraftModdingAPI; | |||
using GamecraftModdingAPI.Utility; | |||
namespace GamecraftModdingAPI.Blocks | |||
{ | |||
public class SpawnPoint : Block | |||
{ | |||
/// <summary> | |||
/// Places a new spawn point. | |||
/// Any valid spawn block type is accepted. | |||
/// This re-implements Block.PlaceNew(...) | |||
/// </summary> | |||
public static new SpawnPoint PlaceNew(BlockIDs block, float3 position, | |||
float3 rotation = default, BlockColors color = BlockColors.Default, byte darkness = 0, | |||
int uscale = 1, float3 scale = default, Player player = null) | |||
{ | |||
if (!(block == BlockIDs.LargeSpawn || block == BlockIDs.SmallSpawn || block == BlockIDs.MediumSpawn || block == BlockIDs.PlayerSpawn)) | |||
{ | |||
throw new BlockTypeException($"Block is not a {typeof(SpawnPoint).Name} block"); | |||
} | |||
if (PlacementEngine.IsInGame && GameState.IsBuildMode()) | |||
{ | |||
try | |||
{ | |||
EGID id = PlacementEngine.PlaceBlock(block, color, darkness, | |||
position, uscale, scale, player, rotation); | |||
Sync(); | |||
return new SpawnPoint(id); | |||
} | |||
catch (Exception e) | |||
{ | |||
Logging.MetaDebugLog(e); | |||
} | |||
} | |||
return null; | |||
} | |||
public SpawnPoint(EGID id) : base(id) | |||
{ | |||
if (!BlockEngine.GetBlockInfoExists<SpawnPointStatsEntityStruct>(this.Id)) | |||
{ | |||
throw new BlockTypeException($"Block is not a {this.GetType().Name} block"); | |||
} | |||
} | |||
public SpawnPoint(uint id) : base(id) | |||
{ | |||
if (!BlockEngine.GetBlockInfoExists<SpawnPointStatsEntityStruct>(this.Id)) | |||
{ | |||
throw new BlockTypeException($"Block is not a {this.GetType().Name} block"); | |||
} | |||
} | |||
// custom spawn point properties | |||
/// <summary> | |||
/// The lives the player spawns in with. | |||
/// </summary> | |||
public uint Lives | |||
{ | |||
get | |||
{ | |||
return BlockEngine.GetBlockInfo<SpawnPointStatsEntityStruct>(Id).lives; | |||
} | |||
set | |||
{ | |||
ref SpawnPointStatsEntityStruct spses = ref BlockEngine.GetBlockInfo<SpawnPointStatsEntityStruct>(Id); | |||
spses.lives = value; | |||
} | |||
} | |||
/// <summary> | |||
/// Whether the spawned player can take damage. | |||
/// </summary> | |||
public bool Damageable | |||
{ | |||
get | |||
{ | |||
return BlockEngine.GetBlockInfo<SpawnPointStatsEntityStruct>(Id).canTakeDamage; | |||
} | |||
set | |||
{ | |||
ref SpawnPointStatsEntityStruct spses = ref BlockEngine.GetBlockInfo<SpawnPointStatsEntityStruct>(Id); | |||
spses.canTakeDamage = value; | |||
} | |||
} | |||
/// <summary> | |||
/// Whether the game over screen will be displayed | |||
/// </summary> | |||
public bool GameOverEnabled | |||
{ | |||
get | |||
{ | |||
return BlockEngine.GetBlockInfo<SpawnPointStatsEntityStruct>(Id).gameOverScreen; | |||
} | |||
set | |||
{ | |||
ref SpawnPointStatsEntityStruct spses = ref BlockEngine.GetBlockInfo<SpawnPointStatsEntityStruct>(Id); | |||
spses.gameOverScreen = value; | |||
} | |||
} | |||
/// <summary> | |||
/// The team id for players who spawn here. | |||
/// </summary> | |||
public byte Team | |||
{ | |||
get | |||
{ | |||
return BlockEngine.GetBlockInfo<SpawnPointIdsEntityStruct>(Id).teamId; | |||
} | |||
set | |||
{ | |||
ref SpawnPointIdsEntityStruct spses = ref BlockEngine.GetBlockInfo<SpawnPointIdsEntityStruct>(Id); | |||
spses.teamId = value; | |||
} | |||
} | |||
} | |||
} |
@@ -0,0 +1,127 @@ | |||
using System; | |||
using RobocraftX.Blocks; | |||
using Gamecraft.Blocks.TimerBlock; | |||
using Svelto.ECS; | |||
using Unity.Mathematics; | |||
using GamecraftModdingAPI; | |||
using GamecraftModdingAPI.Utility; | |||
namespace GamecraftModdingAPI.Blocks | |||
{ | |||
public class Timer : Block | |||
{ | |||
/// <summary> | |||
/// Places a new timer block. | |||
/// </summary> | |||
public static Timer PlaceNew(float3 position, | |||
float3 rotation = default, BlockColors color = BlockColors.Default, byte darkness = 0, | |||
int uscale = 1, float3 scale = default, Player player = null) | |||
{ | |||
if (PlacementEngine.IsInGame && GameState.IsBuildMode()) | |||
{ | |||
try | |||
{ | |||
EGID id = PlacementEngine.PlaceBlock(BlockIDs.Timer, color, darkness, | |||
position, uscale, scale, player, rotation); | |||
Sync(); | |||
return new Timer(id); | |||
} | |||
catch (Exception e) | |||
{ | |||
Logging.MetaDebugLog(e); | |||
} | |||
} | |||
return null; | |||
} | |||
public Timer(EGID id) : base(id) | |||
{ | |||
if (!BlockEngine.GetBlockInfoExists<TimerBlockDataStruct>(this.Id)) | |||
{ | |||
throw new BlockTypeException($"Block is not a {this.GetType().Name} block"); | |||
} | |||
} | |||
public Timer(uint id) : base(id) | |||
{ | |||
if (!BlockEngine.GetBlockInfoExists<TimerBlockDataStruct>(this.Id)) | |||
{ | |||
throw new BlockTypeException($"Block is not a {this.GetType().Name} block"); | |||
} | |||
} | |||
// custom timer properties | |||
/// <summary> | |||
/// The player-specified start time. | |||
/// </summary> | |||
public float Start | |||
{ | |||
get | |||
{ | |||
return BlockEngine.GetBlockInfo<TimerBlockDataStruct>(Id).startTime; | |||
} | |||
set | |||
{ | |||
ref TimerBlockDataStruct tbds = ref BlockEngine.GetBlockInfo<TimerBlockDataStruct>(Id); | |||
tbds.startTime = value; | |||
} | |||
} | |||
/// <summary> | |||
/// The player-specified end time. | |||
/// </summary> | |||
public float End | |||
{ | |||
get | |||
{ | |||
return BlockEngine.GetBlockInfo<TimerBlockDataStruct>(Id).endTime; | |||
} | |||
set | |||
{ | |||
ref TimerBlockDataStruct tbds = ref BlockEngine.GetBlockInfo<TimerBlockDataStruct>(Id); | |||
tbds.endTime = value; | |||
} | |||
} | |||
/// <summary> | |||
/// Whether to display time with millisecond precision. | |||
/// </summary> | |||
public bool DisplayMilliseconds | |||
{ | |||
get | |||
{ | |||
return BlockEngine.GetBlockInfo<TimerBlockDataStruct>(Id).outputFormatHasMS; | |||
} | |||
set | |||
{ | |||
ref TimerBlockDataStruct tbds = ref BlockEngine.GetBlockInfo<TimerBlockDataStruct>(Id); | |||
tbds.outputFormatHasMS = value; | |||
} | |||
} | |||
/// <summary> | |||
/// Current time (as of the last video frame), in milliseconds. | |||
/// </summary> | |||
public int CurrentTime | |||
{ | |||
get | |||
{ | |||
return BlockEngine.GetBlockInfo<TimerBlockLabelCacheEntityStruct>(Id).timeLastRenderFrameMS; | |||
} | |||
set | |||
{ | |||
ref TimerBlockLabelCacheEntityStruct tblces = ref BlockEngine.GetBlockInfo<TimerBlockLabelCacheEntityStruct>(Id); | |||
tblces.timeLastRenderFrameMS = value; | |||
} | |||
} | |||
} | |||
} |