@@ -322,13 +322,9 @@ namespace TechbloxModdingAPI | |||
get => BlockEngine.GetBlockInfo<ScalingEntityStruct>(this).scale.x < 0; | |||
set | |||
{ | |||
BlockEngine.SetBlockInfo(this, (ref ScalingEntityStruct st, bool val) => | |||
st.scale.x = math.abs(st.scale.x) * (val ? -1 : 1), value); | |||
BlockEngine.SetBlockInfo(this, (ref GFXPrefabEntityStructGPUI st, bool val) => | |||
{ | |||
uint prefabId = PrefabsID.GetOrCreatePrefabID((ushort) Type, (byte) Material, 0, value); | |||
st.prefabID = prefabId; | |||
}, value); | |||
var st = BlockEngine.GetBlockInfo<ScalingEntityStruct>(this); | |||
st.scale.x = math.abs(st.scale.x) * (value ? -1 : 1); | |||
BlockEngine.UpdatePrefab(this, (ushort) Type, (byte) Material, value); | |||
} | |||
} | |||
@@ -339,7 +335,8 @@ namespace TechbloxModdingAPI | |||
{ | |||
get | |||
{ | |||
return BlockEngine.GetBlockInfo(this, (DBEntityStruct st) => (BlockIDs) st.DBID, BlockIDs.Invalid); | |||
var opt = BlockEngine.GetBlockInfoOptional<DBEntityStruct>(this); | |||
return opt ? (BlockIDs) opt.Get().DBID : BlockIDs.Invalid; | |||
} | |||
} | |||
@@ -350,18 +347,16 @@ namespace TechbloxModdingAPI | |||
{ | |||
get | |||
{ | |||
byte index = BlockEngine.GetBlockInfo(this, (ColourParameterEntityStruct st) => st.indexInPalette, | |||
byte.MaxValue); | |||
return new BlockColor(index); | |||
var opt = BlockEngine.GetBlockInfoOptional<ColourParameterEntityStruct>(this); | |||
return new BlockColor(opt ? opt.Get().indexInPalette : byte.MaxValue); | |||
} | |||
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); | |||
}, value); | |||
//TODO: Check if setting to 255 works | |||
var color = BlockEngine.GetBlockInfo<ColourParameterEntityStruct>(this); | |||
color.indexInPalette = value.Index; | |||
color.hasNetworkChange = true; | |||
color.paletteColour = BlockEngine.ConvertBlockColor(color.indexInPalette); | |||
} | |||
} | |||
@@ -373,11 +368,9 @@ namespace TechbloxModdingAPI | |||
get => BlockEngine.GetBlockInfo<ColourParameterEntityStruct>(this).paletteColour; | |||
set | |||
{ | |||
BlockEngine.SetBlockInfo(this, (ref ColourParameterEntityStruct color, float4 val) => | |||
{ | |||
color.paletteColour = val; | |||
color.hasNetworkChange = true; | |||
}, value); | |||
ref var color = ref BlockEngine.GetBlockInfo<ColourParameterEntityStruct>(this); | |||
color.paletteColour = value; | |||
color.hasNetworkChange = true; | |||
} | |||
} | |||
@@ -386,9 +379,16 @@ namespace TechbloxModdingAPI | |||
*/ | |||
public BlockMaterial Material | |||
{ | |||
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); | |||
get | |||
{ | |||
var opt = BlockEngine.GetBlockInfoOptional<CubeMaterialStruct>(this); | |||
return opt ? (BlockMaterial) opt.Get().materialId : BlockMaterial.Default; | |||
} | |||
set | |||
{ | |||
BlockEngine.GetBlockInfo<CubeMaterialStruct>(this).materialId = (byte) value; | |||
BlockEngine.UpdatePrefab(this, (ushort) Type, (byte) value, Flipped); //TODO: Test default | |||
} | |||
} | |||
/// <summary> | |||
@@ -397,13 +397,11 @@ namespace TechbloxModdingAPI | |||
/// </summary> | |||
public string Label | |||
{ | |||
get => BlockEngine.GetBlockInfoViewStruct(this, (TextLabelEntityViewStruct st) => st.textLabelComponent?.text); | |||
get => BlockEngine.GetBlockInfoViewComponent<TextLabelEntityViewStruct>(this).textLabelComponent?.text; | |||
set | |||
{ | |||
BlockEngine.SetBlockInfoViewStruct(this, (ref TextLabelEntityViewStruct text, string val) => | |||
{ | |||
if (text.textLabelComponent != null) text.textLabelComponent.text = val; | |||
}, value); | |||
var comp = BlockEngine.GetBlockInfoViewComponent<TextLabelEntityViewStruct>(this).textLabelComponent; | |||
if (comp != null) comp.text = value; | |||
} | |||
} | |||
@@ -421,9 +419,8 @@ namespace TechbloxModdingAPI | |||
get | |||
{ | |||
if (blockGroup != null) return blockGroup; | |||
return blockGroup = BlockEngine.GetBlockInfo(this, | |||
(BlockGroupEntityComponent bgec) => | |||
bgec.currentBlockGroup == -1 ? null : new BlockGroup(bgec.currentBlockGroup, this)); | |||
var bgec = BlockEngine.GetBlockInfo<BlockGroupEntityComponent>(this); | |||
return blockGroup = bgec.currentBlockGroup == -1 ? null : new BlockGroup(bgec.currentBlockGroup, this); | |||
} | |||
set | |||
{ | |||
@@ -434,9 +431,7 @@ namespace TechbloxModdingAPI | |||
return; | |||
} | |||
blockGroup?.RemoveInternal(this); | |||
BlockEngine.SetBlockInfo(this, | |||
(ref BlockGroupEntityComponent bgec, BlockGroup val) => bgec.currentBlockGroup = val?.Id ?? -1, | |||
value); | |||
BlockEngine.GetBlockInfo<BlockGroupEntityComponent>(this).currentBlockGroup = value?.Id ?? -1; | |||
value?.AddInternal(this); | |||
blockGroup = value; | |||
} | |||
@@ -466,10 +461,10 @@ namespace TechbloxModdingAPI | |||
/// <returns>The SimBody of the chunk or null if the block doesn't exist or not in simulation mode.</returns> | |||
public SimBody GetSimBody() | |||
{ | |||
return BlockEngine.GetBlockInfo(this, | |||
(GridConnectionsEntityStruct st) => st.machineRigidBodyId != uint.MaxValue | |||
? new SimBody(st.machineRigidBodyId, st.clusterId) | |||
: null); | |||
var st = BlockEngine.GetBlockInfo<GridConnectionsEntityStruct>(this); | |||
return st.machineRigidBodyId != uint.MaxValue | |||
? new SimBody(st.machineRigidBodyId, st.clusterId) | |||
: null; | |||
} | |||
/// <summary> | |||
@@ -555,7 +550,7 @@ namespace TechbloxModdingAPI | |||
//Lets improve that using delegates | |||
var block = New<T>(Id.entityID, Id.groupID); | |||
if (this.InitData.Group != null) | |||
if (this.InitData.Valid) | |||
{ | |||
block.InitData = this.InitData; | |||
Placed += block.OnPlacedInit; //Reset InitData of new object | |||
@@ -80,6 +80,16 @@ namespace TechbloxModdingAPI.Blocks | |||
return ref entitiesDB.QueryEntityOrDefault<T>(block); | |||
} | |||
internal ref T GetBlockInfo<T>(EcsObjectBase obj) where T : unmanaged, IEntityComponent | |||
{ | |||
return ref entitiesDB.QueryEntityOrDefault<T>(obj); | |||
} | |||
public ref T GetBlockInfoViewComponent<T>(Block block) where T : struct, IEntityViewComponent | |||
{ | |||
return ref entitiesDB.QueryEntityOrDefault<T>(block); | |||
} | |||
public void UpdateDisplayedBlock(EGID id) | |||
{ | |||
if (!BlockExists(id)) return; | |||
@@ -21,8 +21,7 @@ namespace TechbloxModdingAPI.Blocks | |||
{ | |||
get => BlockEngine.GetBlockInfo<DampedSpringReadOnlyStruct>(this).springFrequency; | |||
set => BlockEngine.SetBlockInfo(this, | |||
(ref DampedSpringReadOnlyStruct dsrs, float val) => dsrs.springFrequency = val, value); | |||
set => BlockEngine.GetBlockInfo<DampedSpringReadOnlyStruct>(this).springFrequency = value; | |||
} | |||
/// <summary> | |||
@@ -41,8 +40,7 @@ namespace TechbloxModdingAPI.Blocks | |||
{ | |||
get => BlockEngine.GetBlockInfo<DampedSpringReadOnlyStruct>(this).springDamping; | |||
set => BlockEngine.SetBlockInfo(this, | |||
(ref DampedSpringReadOnlyStruct ljf, float val) => ljf.springDamping = val, value); | |||
set => BlockEngine.GetBlockInfo<DampedSpringReadOnlyStruct>(this).springDamping = value; | |||
} | |||
/// <summary> | |||
@@ -52,8 +50,7 @@ namespace TechbloxModdingAPI.Blocks | |||
{ | |||
get => BlockEngine.GetBlockInfo<DampedSpringReadOnlyStruct>(this).maxExtent; | |||
set => BlockEngine.SetBlockInfo(this, | |||
(ref DampedSpringReadOnlyStruct ljf, float val) => ljf.maxExtent = val, value); | |||
set => BlockEngine.GetBlockInfo<DampedSpringReadOnlyStruct>(this).maxExtent = value; | |||
} | |||
} | |||
} |
@@ -33,8 +33,7 @@ namespace TechbloxModdingAPI.Blocks | |||
set | |||
{ | |||
BlockEngine.SetBlockInfo(this, | |||
(ref MusicBlockDataEntityStruct msdes, byte val) => msdes.trackIndx = val, value); | |||
BlockEngine.GetBlockInfo<MusicBlockDataEntityStruct>(this).trackIndx = value; | |||
} | |||
} | |||
@@ -42,24 +41,22 @@ namespace TechbloxModdingAPI.Blocks | |||
{ | |||
get | |||
{ | |||
return BlockEngine.GetBlockInfo(this, | |||
(MusicBlockDataEntityStruct msdes) => msdes.fmod2DEventPaths.Get<Guid>(msdes.trackIndx)); | |||
var msdes = BlockEngine.GetBlockInfo<MusicBlockDataEntityStruct>(this); | |||
return msdes.fmod2DEventPaths.Get<Guid>(msdes.trackIndx); | |||
} | |||
set | |||
{ | |||
BlockEngine.SetBlockInfo(this, (ref MusicBlockDataEntityStruct msdes, Guid val) => | |||
ref var msdes = ref BlockEngine.GetBlockInfo<MusicBlockDataEntityStruct>(this); | |||
for (byte i = 0; i < msdes.fmod2DEventPaths.Count<Guid>(); i++) | |||
{ | |||
for (byte i = 0; i < msdes.fmod2DEventPaths.Count<Guid>(); i++) | |||
Guid track = msdes.fmod2DEventPaths.Get<Guid>(i); | |||
if (track == value) | |||
{ | |||
Guid track = msdes.fmod2DEventPaths.Get<Guid>(i); | |||
if (track == val) | |||
{ | |||
msdes.trackIndx = i; | |||
break; | |||
} | |||
msdes.trackIndx = i; | |||
break; | |||
} | |||
}, value); | |||
} | |||
} | |||
} | |||
@@ -67,15 +64,13 @@ namespace TechbloxModdingAPI.Blocks | |||
{ | |||
get | |||
{ | |||
return BlockEngine.GetBlockInfo(this, (MusicBlockDataEntityStruct msdes) => | |||
var msdes = BlockEngine.GetBlockInfo<MusicBlockDataEntityStruct>(this); | |||
Guid[] tracks = new Guid[msdes.fmod2DEventPaths.Count<Guid>()]; | |||
for (byte i = 0; i < tracks.Length; i++) | |||
{ | |||
Guid[] tracks = new Guid[msdes.fmod2DEventPaths.Count<Guid>()]; | |||
for (byte i = 0; i < tracks.Length; i++) | |||
{ | |||
tracks[i] = msdes.fmod2DEventPaths.Get<Guid>(i); | |||
} | |||
return tracks; | |||
}); | |||
tracks[i] = msdes.fmod2DEventPaths.Get<Guid>(i); | |||
} | |||
return tracks; | |||
} | |||
} | |||
@@ -88,8 +83,7 @@ namespace TechbloxModdingAPI.Blocks | |||
set | |||
{ | |||
BlockEngine.SetBlockInfo(this, | |||
(ref MusicBlockDataEntityStruct msdes, float val) => msdes.tweakableVolume = val, value); | |||
BlockEngine.GetBlockInfo<MusicBlockDataEntityStruct>(this).tweakableVolume = value; | |||
} | |||
} | |||
@@ -98,14 +92,12 @@ namespace TechbloxModdingAPI.Blocks | |||
get | |||
{ | |||
//Assert.Log("Block exists: " + Exists); | |||
return BlockEngine.GetBlockInfo(this, | |||
(MusicBlockDataEntityStruct msdes) => (ChannelType) msdes.channelType); | |||
return (ChannelType) BlockEngine.GetBlockInfo<MusicBlockDataEntityStruct>(this).channelType; | |||
} | |||
set | |||
{ | |||
BlockEngine.SetBlockInfo(this, | |||
(ref MusicBlockDataEntityStruct msdes, ChannelType val) => msdes.channelType = (byte) val, value); | |||
BlockEngine.GetBlockInfo<MusicBlockDataEntityStruct>(this).channelType = (byte) value; | |||
} | |||
} | |||
@@ -113,33 +105,31 @@ namespace TechbloxModdingAPI.Blocks | |||
{ | |||
get | |||
{ | |||
return BlockEngine.GetBlockInfo(this, | |||
(MusicBlockDataEntityStruct msdes) => msdes.isPlaying); | |||
return BlockEngine.GetBlockInfo<MusicBlockDataEntityStruct>(this).isPlaying; | |||
} | |||
set | |||
{ | |||
BlockEngine.SetBlockInfo(this, (ref MusicBlockDataEntityStruct msdes, bool val) => | |||
ref var msdes = ref BlockEngine.GetBlockInfo<MusicBlockDataEntityStruct>(this); | |||
if (msdes.isPlaying == value) return; | |||
if (value) | |||
{ | |||
if (msdes.isPlaying == val) return; | |||
if (val) | |||
{ | |||
// start playing | |||
EventInstance inst = RuntimeManager.CreateInstance(msdes.fmod2DEventPaths.Get<Guid>(msdes.trackIndx)); | |||
inst.setVolume(msdes.tweakableVolume / 100f); | |||
inst.start(); | |||
msdes.eventHandle = inst.handle; | |||
} | |||
else | |||
{ | |||
// stop playing | |||
EventInstance inst = default(EventInstance); | |||
inst.handle = msdes.eventHandle; | |||
inst.stop(FMOD.Studio.STOP_MODE.ALLOWFADEOUT); | |||
inst.release(); | |||
} | |||
msdes.isPlaying = val; | |||
}, value); | |||
// start playing | |||
EventInstance inst = RuntimeManager.CreateInstance(msdes.fmod2DEventPaths.Get<Guid>(msdes.trackIndx)); | |||
inst.setVolume(msdes.tweakableVolume / 100f); | |||
inst.start(); | |||
msdes.eventHandle = inst.handle; | |||
} | |||
else | |||
{ | |||
// stop playing | |||
EventInstance inst = default(EventInstance); | |||
inst.handle = msdes.eventHandle; | |||
inst.stop(FMOD.Studio.STOP_MODE.ALLOWFADEOUT); | |||
inst.release(); | |||
} | |||
msdes.isPlaying = value; | |||
} | |||
} | |||
} |
@@ -16,14 +16,11 @@ namespace TechbloxModdingAPI.Blocks | |||
public char Identifier | |||
{ | |||
get => (char) BlockEngine.GetBlockInfo<ObjectIdEntityStruct>(this).objectId + 'A'; | |||
get => (char) (BlockEngine.GetBlockInfo<ObjectIdEntityStruct>(this).objectId + 'A'); | |||
set | |||
{ | |||
BlockEngine.SetBlockInfo(this, (ref ObjectIdEntityStruct st, char val) => | |||
{ | |||
st.objectId = (byte) (val - 'A'); | |||
Label = val + ""; //The label isn't updated automatically | |||
}, value); | |||
BlockEngine.GetBlockInfo<ObjectIdEntityStruct>(this).objectId = (byte) (value - 'A'); | |||
Label = value + ""; //The label isn't updated automatically | |||
} | |||
} | |||
@@ -27,8 +27,7 @@ namespace TechbloxModdingAPI.Blocks | |||
set | |||
{ | |||
BlockEngine.SetBlockInfo(this, | |||
(ref SoundSfxBlockDataEntityStruct obj, float val) => obj.tweakableVolume = val, value); | |||
BlockEngine.GetBlockInfo<SoundSfxBlockDataEntityStruct>(this).tweakableVolume = value; | |||
} | |||
} | |||
@@ -41,8 +40,7 @@ namespace TechbloxModdingAPI.Blocks | |||
set | |||
{ | |||
BlockEngine.SetBlockInfo(this, | |||
(ref SoundSfxBlockDataEntityStruct obj, float val) => obj.tweakablePitch = val, value); | |||
BlockEngine.GetBlockInfo<SoundSfxBlockDataEntityStruct>(this).tweakablePitch = value; | |||
} | |||
} | |||
@@ -55,8 +53,7 @@ namespace TechbloxModdingAPI.Blocks | |||
set | |||
{ | |||
BlockEngine.SetBlockInfo(this, | |||
(ref SoundSfxBlockDataEntityStruct obj, bool val) => obj.is3D = val, value); | |||
BlockEngine.GetBlockInfo<SoundSfxBlockDataEntityStruct>(this).is3D = value; | |||
} | |||
} | |||
@@ -64,13 +61,12 @@ namespace TechbloxModdingAPI.Blocks | |||
{ | |||
get | |||
{ | |||
return BlockEngine.GetBlockInfo(this, (SoundSfxBlockDataEntityStruct obj) => (ChannelType)obj.channelType); | |||
return (ChannelType) BlockEngine.GetBlockInfo<SoundSfxBlockDataEntityStruct>(this).channelType; | |||
} | |||
set | |||
{ | |||
BlockEngine.SetBlockInfo(this, | |||
(ref SoundSfxBlockDataEntityStruct obj, ChannelType val) => obj.tweakableVolume = (byte) val, value); | |||
BlockEngine.GetBlockInfo<SoundSfxBlockDataEntityStruct>(this).channelType = (byte) value; | |||
} | |||
} | |||
@@ -83,8 +79,7 @@ namespace TechbloxModdingAPI.Blocks | |||
set | |||
{ | |||
BlockEngine.SetBlockInfo(this, | |||
(ref SoundSfxBlockDataEntityStruct obj, byte val) => obj.soundEffectIndex = val, value); | |||
BlockEngine.GetBlockInfo<SoundSfxBlockDataEntityStruct>(this).soundEffectIndex = value; | |||
} | |||
} | |||
@@ -93,35 +88,36 @@ namespace TechbloxModdingAPI.Blocks | |||
{ | |||
get | |||
{ | |||
return BlockEngine.GetBlockInfo(this, | |||
(SoundSfxBlockDataEntityStruct obj) => obj.is3D ? obj.fmod3DEventPaths.Get<Guid>(obj.soundEffectIndex) : obj.fmod2DEventPaths.Get<Guid>(obj.soundEffectIndex)); | |||
var obj = BlockEngine.GetBlockInfo<SoundSfxBlockDataEntityStruct>(this); | |||
return obj.is3D | |||
? obj.fmod3DEventPaths.Get<Guid>(obj.soundEffectIndex) | |||
: obj.fmod2DEventPaths.Get<Guid>(obj.soundEffectIndex); | |||
} | |||
set | |||
{ | |||
BlockEngine.SetBlockInfo(this, (ref SoundSfxBlockDataEntityStruct obj, Guid val) => | |||
var obj = BlockEngine.GetBlockInfo<SoundSfxBlockDataEntityStruct>(this); | |||
for (byte i = 0; i < obj.fmod2DEventPaths.Count<Guid>(); i++) | |||
{ | |||
for (byte i = 0; i < obj.fmod2DEventPaths.Count<Guid>(); i++) | |||
Guid track = obj.fmod2DEventPaths.Get<Guid>(i); | |||
if (track == value) | |||
{ | |||
Guid track = obj.fmod2DEventPaths.Get<Guid>(i); | |||
if (track == val) | |||
{ | |||
obj.soundEffectIndex = i; | |||
obj.is3D = false; | |||
return; | |||
} | |||
obj.soundEffectIndex = i; | |||
obj.is3D = false; | |||
return; | |||
} | |||
for (byte i = 0; i < obj.fmod3DEventPaths.Count<Guid>(); i++) | |||
} | |||
for (byte i = 0; i < obj.fmod3DEventPaths.Count<Guid>(); i++) | |||
{ | |||
Guid track = obj.fmod3DEventPaths.Get<Guid>(i); | |||
if (track == value) | |||
{ | |||
Guid track = obj.fmod3DEventPaths.Get<Guid>(i); | |||
if (track == val) | |||
{ | |||
obj.soundEffectIndex = i; | |||
obj.is3D = true; | |||
return; | |||
} | |||
obj.soundEffectIndex = i; | |||
obj.is3D = true; | |||
return; | |||
} | |||
}, value); | |||
} | |||
} | |||
} | |||
@@ -130,31 +126,29 @@ namespace TechbloxModdingAPI.Blocks | |||
{ | |||
get | |||
{ | |||
return BlockEngine.GetBlockInfo(this, (SoundSfxBlockDataEntityStruct obj) => | |||
var obj = BlockEngine.GetBlockInfo<SoundSfxBlockDataEntityStruct>(this); | |||
Guid[] tracks = new Guid[obj.fmod2DEventPaths.Count<Guid>()]; | |||
for (byte i = 0; i < tracks.Length; i++) | |||
{ | |||
Guid[] tracks = new Guid[obj.fmod2DEventPaths.Count<Guid>()]; | |||
for (byte i = 0; i < tracks.Length; i++) | |||
{ | |||
tracks[i] = obj.fmod2DEventPaths.Get<Guid>(i); | |||
} | |||
return tracks; | |||
}); | |||
tracks[i] = obj.fmod2DEventPaths.Get<Guid>(i); | |||
} | |||
return tracks; | |||
} | |||
} | |||
public Guid[] Tracks3D | |||
{ | |||
get | |||
{ | |||
return BlockEngine.GetBlockInfo(this, (SoundSfxBlockDataEntityStruct obj) => | |||
var obj = BlockEngine.GetBlockInfo<SoundSfxBlockDataEntityStruct>(this); | |||
Guid[] tracks = new Guid[obj.fmod3DEventPaths.Count<Guid>()]; | |||
for (byte i = 0; i < tracks.Length; i++) | |||
{ | |||
Guid[] tracks = new Guid[obj.fmod3DEventPaths.Count<Guid>()]; | |||
for (byte i = 0; i < tracks.Length; i++) | |||
{ | |||
tracks[i] = obj.fmod2DEventPaths.Get<Guid>(i); | |||
} | |||
return tracks; | |||
}); | |||
tracks[i] = obj.fmod2DEventPaths.Get<Guid>(i); | |||
} | |||
return tracks; | |||
} | |||
} | |||
@@ -167,8 +161,7 @@ namespace TechbloxModdingAPI.Blocks | |||
set | |||
{ | |||
BlockEngine.SetBlockInfo(this, | |||
(ref SoundSfxBlockDataEntityStruct obj, bool val) => obj.isLoopedBlock = val, value); | |||
BlockEngine.GetBlockInfo<SoundSfxBlockDataEntityStruct>(this).isLoopedBlock = value; | |||
} | |||
} | |||
@@ -176,33 +169,33 @@ namespace TechbloxModdingAPI.Blocks | |||
{ | |||
get | |||
{ | |||
return BlockEngine.GetBlockInfo(this, | |||
(SoundSfxBlockDataEntityStruct obj) => obj.isPlaying); | |||
return BlockEngine.GetBlockInfo<SoundSfxBlockDataEntityStruct>(this).isPlaying; | |||
} | |||
set | |||
{ | |||
BlockEngine.SetBlockInfo(this, (ref SoundSfxBlockDataEntityStruct obj, bool val) => | |||
var obj = BlockEngine.GetBlockInfo<SoundSfxBlockDataEntityStruct>(this); | |||
if (obj.isPlaying == value) return; | |||
if (value) | |||
{ | |||
if (obj.isPlaying == val) return; | |||
if (val) | |||
{ | |||
// start playing | |||
EventInstance inst = RuntimeManager.CreateInstance(obj.is3D ? obj.fmod3DEventPaths.Get<Guid>(obj.soundEffectIndex) : obj.fmod2DEventPaths.Get<Guid>(obj.soundEffectIndex)); | |||
inst.setVolume(obj.tweakableVolume / 100f); | |||
inst.start(); | |||
obj.eventHandle = inst.handle; | |||
} | |||
else | |||
{ | |||
// stop playing | |||
EventInstance inst = default(EventInstance); | |||
inst.handle = obj.eventHandle; | |||
inst.stop(FMOD.Studio.STOP_MODE.ALLOWFADEOUT); | |||
inst.release(); | |||
} | |||
obj.isPlaying = val; | |||
}, value); | |||
// start playing | |||
EventInstance inst = RuntimeManager.CreateInstance(obj.is3D | |||
? obj.fmod3DEventPaths.Get<Guid>(obj.soundEffectIndex) | |||
: obj.fmod2DEventPaths.Get<Guid>(obj.soundEffectIndex)); | |||
inst.setVolume(obj.tweakableVolume / 100f); | |||
inst.start(); | |||
obj.eventHandle = inst.handle; | |||
} | |||
else | |||
{ | |||
// stop playing | |||
EventInstance inst = default(EventInstance); | |||
inst.handle = obj.eventHandle; | |||
inst.stop(FMOD.Studio.STOP_MODE.ALLOWFADEOUT); | |||
inst.release(); | |||
} | |||
obj.isPlaying = value; | |||
} | |||
} | |||
} |
@@ -109,7 +109,6 @@ namespace TechbloxModdingAPI.Blocks | |||
/// <returns>The localized port name.</returns> | |||
public string PortName(byte port, bool input) | |||
{ | |||
BlockPortsStruct bps = BlockEngine.GetBlockInfo(this, (BlockPortsStruct a) => a); | |||
PortEntityStruct pes = SignalEngine.GetPortByOffset(this, port, input); | |||
return pes.portNameLocalised; | |||
} | |||
@@ -32,11 +32,9 @@ namespace TechbloxModdingAPI.Blocks | |||
set | |||
{ | |||
if (value == null) value = ""; | |||
BlockEngine.SetBlockInfo(this, (ref TextBlockDataStruct tbds, string val) => | |||
{ | |||
tbds.textCurrent.Set(val); | |||
tbds.textStored.Set(val, true); | |||
}, value); | |||
var tbds = BlockEngine.GetBlockInfo<TextBlockDataStruct>(this); | |||
tbds.textCurrent.Set(value); | |||
tbds.textStored.Set(value, true); | |||
} | |||
} | |||
@@ -50,8 +48,7 @@ namespace TechbloxModdingAPI.Blocks | |||
set | |||
{ | |||
if (value == null) value = ""; | |||
BlockEngine.SetBlockInfo(this, (ref TextBlockDataStruct tbds, string val) => | |||
tbds.textBlockID.Set(val), value); | |||
BlockEngine.GetBlockInfo<TextBlockDataStruct>(this).textBlockID.Set(value); | |||
} | |||
} | |||
} | |||
@@ -8,9 +8,9 @@ namespace TechbloxModdingAPI | |||
/// Represnts a cluster of blocks in time running mode, meaning blocks that are connected either directly or via joints. | |||
/// Only exists if a cluster destruction manager is present. Static blocks like grass and dirt aren't part of a cluster. | |||
/// </summary> | |||
public class Cluster | |||
public class Cluster : EcsObjectBase | |||
{ | |||
public EGID Id { get; } | |||
public override EGID Id { get; } | |||
public Cluster(EGID id) | |||
{ | |||
@@ -23,20 +23,20 @@ namespace TechbloxModdingAPI | |||
public float InitialHealth | |||
{ | |||
get => Block.BlockEngine.GetBlockInfo<HealthEntityComponent>(Id).initialHealth; | |||
set => Block.BlockEngine.GetBlockInfo<HealthEntityComponent>(Id).initialHealth = value; | |||
get => Block.BlockEngine.GetBlockInfo<HealthEntityComponent>(this).initialHealth; | |||
set => Block.BlockEngine.GetBlockInfo<HealthEntityComponent>(this).initialHealth = value; | |||
} | |||
public float CurrentHealth | |||
{ | |||
get => Block.BlockEngine.GetBlockInfo<HealthEntityComponent>(Id).currentHealth; | |||
set => Block.BlockEngine.GetBlockInfo<HealthEntityComponent>(Id).currentHealth = value; | |||
get => Block.BlockEngine.GetBlockInfo<HealthEntityComponent>(this).currentHealth; | |||
set => Block.BlockEngine.GetBlockInfo<HealthEntityComponent>(this).currentHealth = value; | |||
} | |||
public float HealthMultiplier | |||
{ | |||
get => Block.BlockEngine.GetBlockInfo<HealthEntityComponent>(Id).healthMultiplier; | |||
set => Block.BlockEngine.GetBlockInfo<HealthEntityComponent>(Id).healthMultiplier = value; | |||
get => Block.BlockEngine.GetBlockInfo<HealthEntityComponent>(this).healthMultiplier; | |||
set => Block.BlockEngine.GetBlockInfo<HealthEntityComponent>(this).healthMultiplier = value; | |||
} | |||
/// <summary> | |||
@@ -1,6 +1,7 @@ | |||
using Svelto.ECS; | |||
using Techblox.FlyCam; | |||
using TechbloxModdingAPI.Engines; | |||
using TechbloxModdingAPI.Utility; | |||
namespace TechbloxModdingAPI.Players | |||
{ | |||
@@ -12,9 +12,9 @@ namespace TechbloxModdingAPI | |||
/// <summary> | |||
/// A rigid body (like a chunk of connected blocks) during simulation. | |||
/// </summary> | |||
public class SimBody : IEquatable<SimBody>, IEquatable<EGID> | |||
public class SimBody : EcsObjectBase, IEquatable<SimBody>, IEquatable<EGID> | |||
{ | |||
public EGID Id { get; } | |||
public override EGID Id { get; } | |||
/// <summary> | |||
/// The cluster this chunk belongs to, or null if no cluster destruction manager present or the chunk doesn't exist. | |||
@@ -92,26 +92,26 @@ namespace TechbloxModdingAPI | |||
public float InitialHealth | |||
{ | |||
get => Block.BlockEngine.GetBlockInfo<HealthEntityComponent>(Id).initialHealth; | |||
set => Block.BlockEngine.GetBlockInfo<HealthEntityComponent>(Id).initialHealth = value; | |||
get => Block.BlockEngine.GetBlockInfo<HealthEntityComponent>(this).initialHealth; | |||
set => Block.BlockEngine.GetBlockInfo<HealthEntityComponent>(this).initialHealth = value; | |||
} | |||
public float CurrentHealth | |||
{ | |||
get => Block.BlockEngine.GetBlockInfo<HealthEntityComponent>(Id).currentHealth; | |||
set => Block.BlockEngine.GetBlockInfo<HealthEntityComponent>(Id).currentHealth = value; | |||
get => Block.BlockEngine.GetBlockInfo<HealthEntityComponent>(this).currentHealth; | |||
set => Block.BlockEngine.GetBlockInfo<HealthEntityComponent>(this).currentHealth = value; | |||
} | |||
public float HealthMultiplier | |||
{ | |||
get => Block.BlockEngine.GetBlockInfo<HealthEntityComponent>(Id).healthMultiplier; | |||
set => Block.BlockEngine.GetBlockInfo<HealthEntityComponent>(Id).healthMultiplier = value; | |||
get => Block.BlockEngine.GetBlockInfo<HealthEntityComponent>(this).healthMultiplier; | |||
set => Block.BlockEngine.GetBlockInfo<HealthEntityComponent>(this).healthMultiplier = value; | |||
} | |||
/// <summary> | |||
/// Whether the body can be moved or static. | |||
/// </summary> | |||
public bool Static => Block.BlockEngine.GetBlockInfo<MassEntityStruct>(Id).isStatic; //Setting it doesn't have any effect | |||
public bool Static => Block.BlockEngine.GetBlockInfo<MassEntityStruct>(this).isStatic; //Setting it doesn't have any effect | |||
/// <summary> | |||
/// The rigid bodies connected to this one via functional joints (broken ones don't count). | |||
@@ -132,7 +132,7 @@ namespace TechbloxModdingAPI | |||
private ref RigidBodyEntityStruct GetStruct() | |||
{ | |||
return ref Block.BlockEngine.GetBlockInfo<RigidBodyEntityStruct>(Id); | |||
return ref Block.BlockEngine.GetBlockInfo<RigidBodyEntityStruct>(this); | |||
} | |||
public override string ToString() | |||
@@ -0,0 +1,55 @@ | |||
using Svelto.ECS; | |||
using Svelto.ECS.Hybrid; | |||
using TechbloxModdingAPI.Blocks; | |||
namespace TechbloxModdingAPI.Utility | |||
{ | |||
public static class ManagedApiExtensions | |||
{ | |||
/// <summary> | |||
/// Attempts to query an entity and returns an optional that contains the result if succeeded. | |||
/// <b>This overload does not take initializer data into account.</b> | |||
/// </summary> | |||
/// <param name="entitiesDB">The entities DB</param> | |||
/// <param name="egid">The EGID to query</param> | |||
/// <typeparam name="T">The component type to query</typeparam> | |||
/// <returns>An optional that contains the result on success or is empty if not found</returns> | |||
public static OptionalRef<T> QueryEntityOptional<T>(this EntitiesDB entitiesDB, EGID egid) | |||
where T : struct, IEntityViewComponent | |||
{ | |||
return entitiesDB.TryQueryEntitiesAndIndex<T>(egid, out uint index, out var array) | |||
? new OptionalRef<T>(array, index) | |||
: new OptionalRef<T>(); | |||
} | |||
/// <summary> | |||
/// Attempts to query an entity and returns the result or a dummy value that can be modified. | |||
/// </summary> | |||
/// <param name="entitiesDB"></param> | |||
/// <param name="obj"></param> | |||
/// <typeparam name="T"></typeparam> | |||
/// <returns></returns> | |||
public static OptionalRef<T> QueryEntityOptional<T>(this EntitiesDB entitiesDB, EcsObjectBase obj) | |||
where T : struct, IEntityViewComponent | |||
{ | |||
var opt = QueryEntityOptional<T>(entitiesDB, obj.Id); | |||
return opt ? opt : new OptionalRef<T>(obj, true); | |||
} | |||
/// <summary> | |||
/// Attempts to query an entity and returns the result or a dummy value that can be modified. | |||
/// </summary> | |||
/// <param name="entitiesDB"></param> | |||
/// <param name="obj"></param> | |||
/// <typeparam name="T"></typeparam> | |||
/// <returns></returns> | |||
public static ref T QueryEntityOrDefault<T>(this EntitiesDB entitiesDB, EcsObjectBase obj) | |||
where T : struct, IEntityViewComponent | |||
{ | |||
var opt = QueryEntityOptional<T>(entitiesDB, obj.Id); | |||
if (opt) return ref opt.Get(); | |||
if (obj.InitData.Valid) return ref obj.InitData.Initializer(obj.Id).GetOrCreate<T>(); | |||
return ref opt.Get(); //Default value | |||
} | |||
} | |||
} |
@@ -3,10 +3,11 @@ using TechbloxModdingAPI.Blocks; | |||
namespace TechbloxModdingAPI.Utility | |||
{ | |||
public static class ApiExtensions | |||
public static class NativeApiExtensions | |||
{ | |||
/// <summary> | |||
/// Attempts to query an entity and returns an optional that contains the result if succeeded. | |||
/// <b>This overload does not take initializer data into account.</b> | |||
/// </summary> | |||
/// <param name="entitiesDB">The entities DB</param> | |||
/// <param name="egid">The EGID to query</param> | |||
@@ -31,7 +32,7 @@ namespace TechbloxModdingAPI.Utility | |||
where T : unmanaged, IEntityComponent | |||
{ | |||
var opt = QueryEntityOptional<T>(entitiesDB, obj.Id); | |||
return opt ? opt : new OptionalRef<T>(obj); | |||
return opt ? opt : new OptionalRef<T>(obj, true); | |||
} | |||
/// <summary> |
@@ -1,44 +1,53 @@ | |||
using System; | |||
using System.Collections; | |||
using System.Collections.Generic; | |||
using System.Linq; | |||
using System.Linq.Expressions; | |||
using TechbloxModdingAPI.Blocks; | |||
using System.Runtime.InteropServices; | |||
using Svelto.DataStructures; | |||
using Svelto.ECS; | |||
namespace TechbloxModdingAPI | |||
namespace TechbloxModdingAPI.Utility | |||
{ | |||
public ref struct OptionalRef<T> where T : unmanaged, IEntityComponent | |||
[StructLayout(LayoutKind.Explicit)] //Make the array and managedArray fields take up the same space | |||
public ref struct OptionalRef<T> where T : struct, IEntityComponent | |||
{ | |||
private bool exists; | |||
private NB<T> array; | |||
private uint index; | |||
private EntityInitializer initializer; | |||
[FieldOffset(0)] private readonly State state; | |||
[FieldOffset(1)] private readonly uint index; | |||
[FieldOffset(5)] private NB<T> array; | |||
[FieldOffset(5)] private MB<T> managedArray; | |||
[FieldOffset(1)] private readonly EntityInitializer initializer; | |||
//The possible fields are: (index && (array || managedArray)) || initializer | |||
public OptionalRef(NB<T> array, uint index) | |||
{ | |||
exists = true; | |||
state = State.Native; | |||
this.array = array; | |||
this.index = index; | |||
initializer = default; | |||
} | |||
public OptionalRef(MB<T> array, uint index) | |||
{ | |||
state = State.Managed; | |||
managedArray = array; | |||
this.index = index; | |||
initializer = default; | |||
this.array = default; | |||
} | |||
/// <summary> | |||
/// Wraps the initializer data, if present. | |||
/// </summary> | |||
/// <param name="obj">The object with the initializer</param> | |||
public OptionalRef(EcsObjectBase obj) | |||
/// <param name="unmanaged">Whether the struct is unmanaged</param> | |||
public OptionalRef(EcsObjectBase obj, bool unmanaged) | |||
{ | |||
if (obj.InitData.Valid) | |||
{ | |||
initializer = obj.InitData.Initializer(obj.Id); | |||
exists = true; | |||
state = (unmanaged ? State.Native : State.Managed) | State.Initializer; | |||
} | |||
else | |||
{ | |||
initializer = default; | |||
exists = false; | |||
state = State.Empty; | |||
} | |||
array = default; | |||
index = default; | |||
@@ -50,31 +59,36 @@ namespace TechbloxModdingAPI | |||
/// <returns>The value or the default value</returns> | |||
public ref T Get() | |||
{ | |||
if (!exists) return ref CompRefCache<T>.Default; | |||
if (initializer.EGID == EGID.Empty) | |||
return ref array[index]; | |||
return ref initializer.GetOrCreate<T>(); | |||
if (state == State.Empty) return ref CompRefCache.Default; | |||
if ((state & State.Initializer) != State.Empty) return ref initializer.GetOrCreate<T>(); | |||
if ((state & State.Native) != State.Empty) return ref array[index]; | |||
return ref managedArray[index]; | |||
} | |||
public bool Exists => exists; | |||
public bool Exists => state != State.Empty; | |||
public static implicit operator T(OptionalRef<T> opt) => opt.Get(); | |||
public static implicit operator bool(OptionalRef<T> opt) => opt.exists; | |||
/*public delegate ref TR Mapper<TR>(ref T component) where TR : unmanaged; | |||
public unsafe delegate TR* PMapper<TR>(T* component) where TR : unmanaged; | |||
public unsafe OptionalRef<TR> Map<TR>(PMapper<TR> mapper) where TR : unmanaged => | |||
exists ? new OptionalRef<TR>(ref *mapper(pointer)) : new OptionalRef<TR>();*/ | |||
public static implicit operator bool(OptionalRef<T> opt) => opt.state != State.Empty; | |||
/// <summary> | |||
/// Creates an instance of a struct T that can be referenced. | |||
/// </summary> | |||
/// <typeparam name="TR">The struct type to cache</typeparam> | |||
private struct CompRefCache<TR> where TR : unmanaged | |||
internal struct CompRefCache | |||
{ | |||
public static T Default; | |||
} | |||
/// <summary> | |||
/// A byte that holds state in its bits. | |||
/// </summary> | |||
[Flags] | |||
private enum State : byte | |||
{ | |||
public static TR Default; | |||
Empty, | |||
Native, | |||
Managed, | |||
Initializer = 4 | |||
} | |||
} | |||
} |