Jump to content

A way to add tracks?


Recommended Posts

13 minutes ago, niston said:

I wish there was a thumbs up icon to select.

*sigh* have this instead:

  Reveal hidden contents

Sjd3Do6.png

 

In general, we make one long panel for the numbers. I just think that the panel itself should be narrower. The numbers don't have to be gigantic. Dark glass panel, small numbers in its center. Not the entire length of the panel. Huge numbers like red clown noses will look in combination with touch buttons. Vintage from AliExpress.

Link to comment
Share on other sites

33 minutes ago, niston said:

I agree.

What style do you want for the numbers? The original's 7 segment LED style?

Which one is easier for you to implement. Let it be what is easier to do. The main thing is that the numbers are not gigantic. I think when I make the model... When there is a ready segment for placing the panel... Then we will deal with these numbers step by step. The main thing is that you don’t have to redo it again.

Link to comment
Share on other sites

  • Easiest is just using the nixies as is - very little additional work, as rescaling is just a few clicks in nifskope.
  • Also very easy for me: You make an animated model of a single digit 7 segment display, exactly as specified earlier. I can very easily integrate it.
  • Bit of work for whomever choose to do it: Making new textures for the existing nixies, so they won't look like nixies anymore.


I suggest we simply use existing nixies for now. We can still change it later if we feel like.
You can experiment with the NIFs I sent you and determine scale of the individual nixie element as you see fit.
Once you know scale multiplier, I can apply it on my side in nifskope. Limitation: I can only do unform scale in niskope.
You can also determine placement of each element by positioning NiNodes to which the elements attach to.

 

Link to comment
Share on other sites

6 minutes ago, niston said:
  • Easiest is just using the nixies as is - very little additional work, as rescaling is just a few clicks in nifskope.
  • Also very easy for me: You make an animated model of a single digit 7 segment display, exactly as specified earlier. I can very easily integrate it.
  • Bit of work for whomever choose to do it: Making new textures for the existing nixies, so they won't look like nixies anymore.


I suggest we simply use existing nixies for now. We can still change it later if we feel like.
You can experiment with the NIFs I sent you and determine scale of the individual nixie element as you see fit.
Once you know scale multiplier, I can apply it on my side in nifskope.
You can also determine placement of each element by positioning NiNodes to which the elements attach to.

 

Yes. Let's do so.

Link to comment
Share on other sites

Current state of NetLink:SOUL:Protocol class:

Spoiler
Scriptname NetLink:SOUL:Protocol extends NetLink:API:NetworkLayerBase

; audio-team SOUL (SOUTHLINK) protocol V1.0
; custom scripting by niston

; Implementation version info
Int Property IMPL_VERSION_MAJOR = 0 AutoReadOnly Hidden				; SOUL implementation version major (should match NetLink LinkLayer version)
Int Property IMPL_VERSION_MINOR = 54 AutoReadOnly Hidden			; SOUL implementation version minor (should match NetLink LinkLayer version)

; SOUL protocol identifiers
Int Property NETLINK_FRAMETYPE_SOUL = 8028 AutoReadOnly Hidden		; SOUL protocol uses netlink frametype 8028
Int Property PROTOCOL_VERSION = 1 AutoReadOnly Hidden				; SOUL protocol version
String Property PROTOCOL_MAGIC = "SOUL" AutoReadOnly Hidden			; SOUL packet magic

; SOUL error codes
Int Property ERROR_SOUL_NOTSTARTED = -3100 AutoReadOnly Hidden		; SOUL protocol not started
Int Property ERROR_SOUL_NOPOWER = -3101 AutoReadOnly Hidden			; SOUL device not powered
Int Property ERROR_SOUL_LINKLAYER = -3102 AutoReadOnly Hidden		; LinkLayer reference is unavailable

; SOUL packet types
Int Property SOUL_PACKETTYPE_VC = 1 AutoReadonly Hidden				; Virtual Circuit packet
Int Property SOUL_PACKETTYPE_SINK = 3 AutoReadonly Hidden	    	; SINK packet
Int Property SOUL_PACKETTYPE_CONTROL = 5 AutoReadOnly Hidden		; CONTROL packet
Int Property SOUL_PACKETTYPE_SOURCE = 7 AutoReadOnly Hidden			; SOURCE packet

; SOUL device types
Int Property SOUL_DEVICETYPE_UNSPECIFIED = 0 AutoReadOnly Hidden	; SOUL device type not specified
Int Property SOUL_DEVICETYPE_SOURCE = 1 AutoReadOnly Hidden			; SOURCE type SOUL device
Int Property SOUL_DEVICETYPE_CONTROL = 2 AutoReadOnly Hidden		; CONTROL type SOUL device
Int Property SOUL_DEVICETYPE_SINK = 3 AutoReadOnly Hidden			; SINK type SOUL device
Int Property SOUL_DEVICETYPE_REMOTE = 4 AutoReadOnly Hidden			; REMOTE type SOUL device

; SOUL source types
Int Property SOUL_SOURCETYPE_RADIO = 1 AutoReadOnly Hidden			; RADIO source type
Int Property SOUL_SOURCETYPE_DESCR = 2 AutoReadOnly Hidden			; DESCRIPTOR source type

; Virtual Circuit Control
Int Property VC_SYNCREQ = 1 AutoReadOnly Hidden						; synchronization request
Int Property VC_SYNCACK = 2 AutoReadOnly Hidden						; synchronization acknowledgement
Int Property VC_SYNCEST = 3 AutoReadOnly Hidden 					; synchronization established
Int Property VC_SYNCCHK = 4 AutoReadOnly Hidden						; synchronization test
Int Property VC_SYNCBYE = 99 AutoReadOnly Hidden   					; teardown notification

; Sink Control
Int Property SINK_CMD_CLEAR = 1 AutoReadOnly Hidden		; clear (stop) emitter
Int Property SINK_CMD_SYNC = 2 AutoReadOnly Hidden		; synchronize emitter
Int Property SINK_CMD_PLAYBACK = 5 AutoReadOnly Hidden	; clear any existing emitter, create new emitter for SOUL Zone and start playback
Int Property SINK_CMD_UPDATE = 6 AutoReadOnly Hidden	; update zone emitter
Int Property SINK_CMD_VOLCNTRL = 11 AutoReadOnly Hidden ; update zone emitter volume


String Property SystemNameDefault = "MySystem" Auto Const
{ SOUL Default System Name }

Bool Property EnableRxRaw = false Auto Hidden
Bool Property EnableRxVC = true Auto Hidden
Bool Property EnableRxSink = true Auto Hidden
Bool Property EnableRxControl = true Auto Hidden
Bool Property EnableRxSource = true Auto Hidden


; Local SOUL System Name
String _SystemName
String Property SystemName
	String Function Get()
		Return _SystemName
	EndFunction
	Function Set(String value)		
		_SystemName = value
		; TODO: notification
	EndFunction
EndProperty


Struct SOULSourceDef	
	String SourceName			; Name of source component
	Int SourceType				; SOUL source type
	Var SourceData				; source data
EndStruct

Struct SOULSourceDataRadioDef	; RADIO source	
	Float Frequency				; radio frequency
	Bool Boost					; volume boost enable
EndStruct

Struct SOULSourceDataDescrDef	; DESCRIPTOR source
	Sound Descriptor			; sound descriptor
	ObjectReference SyncRef		; emitter synchronization reference	
	Int Position				; playback position
	Int Duration				; total duration
	Bool Paused					; source paused
EndStruct

Struct SOULZoneDef				; speaker ZONE
	String ZoneName				; zone name
	SourceDef Source			; selected listening source
	Float VolumeL				; playback volume left hand
	Float VolumeR				; playback volume right hand
EndStruct

Struct SOULPacket
	String Magic
	Int Version
	String System
	Int PacketType
	Var Data
EndStruct

Struct SOULPacketVCType
	Int Command
EndStruct

Struct SOULPacketSinkType
	String Zone
	Int Command
	Var Data
EndStruct

Struct SOULPacketSourceType
	String Name
	Int Command
	Var Data
EndStruct

Struct DataVolumeControl
	Float VolumeL
	Float VolumeR
EndStruct


; L3 protocol overrides
String Function GetIdentifier()
	Return "SOUL"
EndFunction

String Function GetIdentifierDesc()
	Return "SOUTHLINK"
EndFunction

Int Function GetVersionMajor()
	Return IMPL_VERSION_MAJOR
EndFunction

Int Function GetVersionMinor()
	Return IMPL_VERSION_MINOR
EndFunction

; SOUL packet received event
CustomEvent Started
CustomEvent Stopping
CustomEvent SOULReceiveRaw
CustomEvent SOULReceiveVC
CustomEvent SOULReceiveSink

Group SOULProtocolSettings
	Bool Property RequirePower = true Auto Const
	{ If true, attached reference must be powered for SOUL to work }
EndGroup

; true while SOUL protocol is started
Bool Property IsStarted Hidden
	Bool Function Get()
		Return bStarted
	EndFunction
EndProperty

Bool bStarted = false

Event OnInit()
	Int result = Start()
EndEvent

Event OnWorkshopObjectPlaced(ObjectReference refWorkshop)
	Int result = Start()
EndEvent

Event OnWorkshopObjectDestroyed(ObjectReference refWorkshop)
	Stop()
EndEvent

Event NetLink:LinkLayer.Started(NetLink:LinkLayer refLinkLayer, Var[] noneArgs)
	; link layer has started
	If (bStarted)	; SOUL protocol still started?
	
		; register SOUL protocol with LinkLayer
		_FrameTypeRegistration()
	EndIf
EndEvent

Event NetLink:LinkLayer.Stopping(NetLink:LinkLayer refLinkLayer, Var[] noneArgs)
	If (bStarted)
		; unregister SOUL protocol from LinkLayer
		_FrameTypeRegistration(unregisterFrameType = true)	
	EndIf
EndEvent

Int Function Start()
	If (!IsBoundGameObjectAvailable())
		Return ERROR_UNAVAILABLE
	EndIf
	
	If (bStarted)
		; already started
		Return OK_NOERROR
	EndIf	
	
	; start networklayer base
	Int result = Parent.Start()
	If (!CheckSuccessCode(result))
		; failed
		Return result
	EndIf
	
	; register for link layer lifecycle events
	RegisterForCustomEvent(LinkLayer, "Started")
	RegisterForCustomEvent(LinkLayer, "Stopping")
	
	; if linklayer is started, register networklayer frametypes
	If (LinkLayer.IsStarted)
		result = _FrameTypeRegistration()
		If (!CheckSuccessCode(result))
			Debug.Trace(Self + ": ERROR - Protocol Start failed: FTR for FrameType (" + LinkLayer.NETLINK_FRAMETYPE_SOUL + ") failed with code (" + ResolveErrorCode(result) + ").")
			Return result
		EndIf
	EndIf
	
	;Debug.Trace(Self + ": DEBUG - Protocol scriptname is (" + NetworkLayerScriptname + ").")
	
	; log chatter
	Debug.Trace(Self + ": INFO - Protocol started.")
	
	; SOUL protocol started
	bStarted = true
	
	SendCustomEvent("Started", new Var[0])
	
	Return OK_NOERROR
EndFunction

Function Stop()
	If (bStarted)
		; SOUL protocol no longer started
		bStarted = false

		SendCustomEvent("Stopping", new Var[0])

		; unregister this networklayer from linklayer
		If (LinkLayer != none)

			If (LinkLayer.IsStarted)
				_FrameTypeRegistration(unregisterFrameType = true)
			EndIf
		
			; unregister link layer lifecycle events
			UnRegisterForCustomEvent(LinkLayer, "Started")
			UnRegisterForCustomEvent(LinkLayer, "Stopping")
		EndIf
		
		; stop NetworkLayer base class
		Parent.Stop()

		; log chatter
		Debug.Trace(Self + ": INFO - Protocol stopped.")		
	EndIf
EndFunction

 send a SOUL SINK command to a system/zone
Int Function SendCommandSink(ObjectReference refRecipient, String zoneName, Int commandId, Var commandData)
	If (!_IsDevicePowered())
		Debug.Trace(Self + ": WARNING - SendCommandSink() skipped: Device not powered.")
		Return ERROR_SOUL_NOPOWER
	EndIf
	If (!bStarted)
		Debug.Trace(Self + ": ERROR - SendCommandSink() failed: Protocol not started.")
		Return ERROR_SOUL_NOTSTARTED	
	EndIf

	SOULPacketSinkType outPacket = new SOULPacketSinkType
	outPacket.Zone = zoneName
	outPacket.Command = commandId
	outPacket.Data = commandData
	
	Return SendSOULPacket(refRecipient, systemName, outPacket)
EndFunction

Int Function SendSOULPacket(ObjectReference refRecipient, Int packetType, Var packetData)
	SOULPacket outPacket = new SOULPacket
	
	outPacket.Magic = PROTOCOL_MAGIC
	outPacket.Version = PROTOCOL_VERSION
	outPacket.System = _SystemName
	outPacket.PacketType = packetType
	outPacket.Data = packetData	
	
	If (!bStarted)
		Debug.Trace(Self + ": ERROR - SendSOULPacket() failed: Protocol not started.")
		Return ERROR_SOUL_NOTSTARTED
	EndIf
	If (!_IsDevicePowered())
		Debug.Trace(Self + ": WARNING - SendSinkCommand() skipped: Device not powered.")
		Return ERROR_SOUL_NOPOWER		
	EndIf

	Debug.Trace(Self + ": DEBUG - Sending SOUL Packet (" + outPacket + ") for System (" + outPacket.System + ") to Link Layer...")
	Int success = LinkLayer.LinkSend(refRecipient, NETLINK_FRAMETYPE_SOUL, outPacket)
	Return success	
EndFunction

; function to transmit "raw" SOUL packets
Int Function SendSOULPacketRaw(ObjectReference refRecipient, SOULPacket outPacket)
	If (!bStarted)
		Debug.Trace(Self + ": ERROR - SendSOULPacketRaw() failed: SOUL protocol not started.")
		Return ERROR_SOUL_NOTSTARTED
	EndIf
	If (!_IsDevicePowered())
		Return ERROR_SOUL_NOPOWER
	EndIf

	Debug.Trace(Self + ": DEBUG - Sending SOUL Packet (" + outPacket + ") for System (" + outPacket.System + ") to Link Layer...")
	Int success = LinkLayer.LinkSend(refRecipient, NETLINK_FRAMETYPE_SOUL, outPacket)
	Return success	
EndFunction

Function OnLinkReceive(Var[] eventArgs)
	; SUP accelerated version
	NetLink:API:LinkLayerBase srcLinkLayer = eventArgs[0] as NetLink:LinkLayer
	NetLink:API:LinkLayerBase:NetLinkFrame inFrame = eventArgs[1] as NetLink:API:LinkLayerBase:NetLinkFrame

	; RX filters
	If (srcLinkLayer == none)
		; missing or invalid source linklayer: discard frame.
		Return
	EndIf
	If (inFrame == none)
		; missing or non-netlink frame: discard.
		Return
	EndIf
	If (inFrame.FrameType != NETLINK_FRAMETYPE_SOUL)
		; not a SOUL type NetLink Frame: discard.
		Return
	EndIf
	
	; protocol started?
	If (!bStarted)
		;Debug.Trace(Self + ": WARNING - SOUL type Frame discarded: Protocol not started.")
		Return
	EndIf
	
	; device powered?
	If (!_IsDevicePowered())
		;Debug.Trace(Self + ": WARNING - SOUL type Frame discarded: Device not powered.")
		Return
	EndIf

	; SOUL FrameType received, extract SOUL packet payload
	SOULPacket soulPacket = inFrame.Payload as SOULPacket	

	If (soulPacket == none)
		Debug.Trace(Self + ": WARNING - SOUL type Frame discarded: Null Payload.")
		Return
	EndIf
	If (soulPacket.Magic != PROTOCOL_MAGIC)
		Debug.Trace(Self + ": WARNING - SOUL type Frame discarded: Invalid MAGIC (" + soulPacket.Magic + ").")
		Return	
	EndIf

	; SOUL type frame has proper SOUL protocol version?
	If (soulPacket.Version != PROTOCOL_VERSION)								
		Debug.Trace(Self + ": WARNING - SOUL type Frame discarded: SOUL Protocol version (" + soulPacket.VERSION + ") not supported.")
		Return
	EndIf
	
	;Debug.Trace(Self + ": DEBUG - Received SOUL type Frame from Link Layer.")

	If (EnableRxRaw)
		; generate raw rx event
		Var[] outEventArgs = new Var[3]
		outEventArgs[0] = inFrame.Source			; netlink source ref
		outEventArgs[1] = inFrame.Destination		; netlink destination ref
		outEventArgs[2] = soulPacket				; SOUL packet received
		SendCustomEvent("SOULReceiveRaw", outEventArgs)
	EndIf
	
	; decode PacketType
	If ((soulPacket.PacketType == SOUL_PACKETTYPE_VC) & EnableRxVC) 		; # virtual circuit packet
		rxVCCtrl = inFrame.Data as SOULPacketVCType
		If (rxVCCtrl == none)
			Debug.Trace(Self + ": WARNING - SOUL type Frame discarded: Invalid or missing Data segment for PacketType (SOUL_PACKETTYPE_VC).")
			Return
		EndIf
		; TODO: actual implementation
	
	ElseIf ((inFrame.PacketType == SOUL_PACKETTYPE_SINK) & EnableRxSink)	; # sink packet
		rxSinkCtrl = inFrame.Data as SOULPacketSinkType
		If (rxSinkCtrl == none)
			Debug.Trace(Self + ": WARNING - SOUL type Frame discarded: Invalid or missing Data segment for PacketType (SOUL_PACKETTYPE_SINK).")
			Return
		EndIf
		
		Var[] rxSCEventArgs = new Var[6]
		rxSCEventArgs[0] = inFrame.Source
		rxSCEventArgs[1] = inFrame.Destination
		rxSCEventArgs[2] = soulPacket.System
		rxSCEventArgs[3] = rxSinkCtrl.Zone
		rxSCEventArgs[4] = rxSinkCtrl.Command
		rxSCEventArgs[5] = rxSinkCtrl.Data
		SendCustomEvent("SOULReceiveSink", rxSCEventArgs)
	
	ElseIf ((inFrame.PacketType == SOUL_PACKETTYPE_CONTROL) & EnableRxControl)
	
	ElseIf ((inFrame.PacketType == SOUL_PACKETTYPE_SOURCE) & EnableRxSource)
	
	Else
		Debug.Trace(Self + ": WARNING - SOUL type Frame discarded: Unknown PacketType (" + inFrame.PacketType + ").")
	EndIf
EndFunction


String Function ResolveErrorCode(Int code)				; resolve SOUL protocol error codes
	If (code == OK_NOERROR)
		Return "OK_NOERROR"	
	ElseIf (code == ERROR_SOUL_NOPOWER)
		Return "ERROR_SOUL_NOPOWER"
	ElseIf (code == ERROR_SOUL_NOTSTARTED)
		Return "ERROR_SOUL_NOTSTARTED"
	Else
		Return Parent.ResolveErrorCode(code)
	EndIf
EndFunction

; internal functions
Bool Function _IsDevicePowered()
	If (!RequirePower)
		Return True
	Else
		Return IsPowered()
	EndIf
EndFunction

Int Function _FrameTypeRegistration(Bool unregisterFrameType = false)
	If (!LinkLayer)
		Return ERROR_SOUL_LINKLAYER
	EndIf
	Int nlCode = OK_NOERROR
	If (unregisterFrameType == true)	; unregister frame type
		LinkLayer.FTRUnregisterNetworkLayerForFrameType(Self, LinkLayer.NETLINK_FRAMETYPE_SOUL)
	Else
		nlCode = LinkLayer.FTRRegisterNetworkLayerForFrameType(Self, LinkLayer.NETLINK_FRAMETYPE_SOUL)
	EndIf
	Return nlCode
EndFunction

 

Unfinished. Didn't even try to compile.

Link to comment
Share on other sites

Posted (edited)
On 5/28/2024 at 11:44 PM, niston said:

Current state of NetLink:SOUL:Protocol class:

  Reveal hidden contents
Scriptname NetLink:SOUL:Protocol extends NetLink:API:NetworkLayerBase

; audio-team SOUL (SOUTHLINK) protocol V1.0
; custom scripting by niston

; Implementation version info
Int Property IMPL_VERSION_MAJOR = 0 AutoReadOnly Hidden				; SOUL implementation version major (should match NetLink LinkLayer version)
Int Property IMPL_VERSION_MINOR = 54 AutoReadOnly Hidden			; SOUL implementation version minor (should match NetLink LinkLayer version)

; SOUL protocol identifiers
Int Property NETLINK_FRAMETYPE_SOUL = 8028 AutoReadOnly Hidden		; SOUL protocol uses netlink frametype 8028
Int Property PROTOCOL_VERSION = 1 AutoReadOnly Hidden				; SOUL protocol version
String Property PROTOCOL_MAGIC = "SOUL" AutoReadOnly Hidden			; SOUL packet magic

; SOUL error codes
Int Property ERROR_SOUL_NOTSTARTED = -3100 AutoReadOnly Hidden		; SOUL protocol not started
Int Property ERROR_SOUL_NOPOWER = -3101 AutoReadOnly Hidden			; SOUL device not powered
Int Property ERROR_SOUL_LINKLAYER = -3102 AutoReadOnly Hidden		; LinkLayer reference is unavailable

; SOUL packet types
Int Property SOUL_PACKETTYPE_VC = 1 AutoReadonly Hidden				; Virtual Circuit packet
Int Property SOUL_PACKETTYPE_SINK = 3 AutoReadonly Hidden	    	; SINK packet
Int Property SOUL_PACKETTYPE_CONTROL = 5 AutoReadOnly Hidden		; CONTROL packet
Int Property SOUL_PACKETTYPE_SOURCE = 7 AutoReadOnly Hidden			; SOURCE packet

; SOUL device types
Int Property SOUL_DEVICETYPE_UNSPECIFIED = 0 AutoReadOnly Hidden	; SOUL device type not specified
Int Property SOUL_DEVICETYPE_SOURCE = 1 AutoReadOnly Hidden			; SOURCE type SOUL device
Int Property SOUL_DEVICETYPE_CONTROL = 2 AutoReadOnly Hidden		; CONTROL type SOUL device
Int Property SOUL_DEVICETYPE_SINK = 3 AutoReadOnly Hidden			; SINK type SOUL device
Int Property SOUL_DEVICETYPE_REMOTE = 4 AutoReadOnly Hidden			; REMOTE type SOUL device

; SOUL source types
Int Property SOUL_SOURCETYPE_RADIO = 1 AutoReadOnly Hidden			; RADIO source type
Int Property SOUL_SOURCETYPE_DESCR = 2 AutoReadOnly Hidden			; DESCRIPTOR source type

; Virtual Circuit Control
Int Property VC_SYNCREQ = 1 AutoReadOnly Hidden						; synchronization request
Int Property VC_SYNCACK = 2 AutoReadOnly Hidden						; synchronization acknowledgement
Int Property VC_SYNCEST = 3 AutoReadOnly Hidden 					; synchronization established
Int Property VC_SYNCCHK = 4 AutoReadOnly Hidden						; synchronization test
Int Property VC_SYNCBYE = 99 AutoReadOnly Hidden   					; teardown notification

; Sink Control
Int Property SINK_CMD_CLEAR = 1 AutoReadOnly Hidden		; clear (stop) emitter
Int Property SINK_CMD_SYNC = 2 AutoReadOnly Hidden		; synchronize emitter
Int Property SINK_CMD_PLAYBACK = 5 AutoReadOnly Hidden	; clear any existing emitter, create new emitter for SOUL Zone and start playback
Int Property SINK_CMD_UPDATE = 6 AutoReadOnly Hidden	; update zone emitter
Int Property SINK_CMD_VOLCNTRL = 11 AutoReadOnly Hidden ; update zone emitter volume


String Property SystemNameDefault = "MySystem" Auto Const
{ SOUL Default System Name }

Bool Property EnableRxRaw = false Auto Hidden
Bool Property EnableRxVC = true Auto Hidden
Bool Property EnableRxSink = true Auto Hidden
Bool Property EnableRxControl = true Auto Hidden
Bool Property EnableRxSource = true Auto Hidden


; Local SOUL System Name
String _SystemName
String Property SystemName
	String Function Get()
		Return _SystemName
	EndFunction
	Function Set(String value)		
		_SystemName = value
		; TODO: notification
	EndFunction
EndProperty


Struct SOULSourceDef	
	String SourceName			; Name of source component
	Int SourceType				; SOUL source type
	Var SourceData				; source data
EndStruct

Struct SOULSourceDataRadioDef	; RADIO source	
	Float Frequency				; radio frequency
	Bool Boost					; volume boost enable
EndStruct

Struct SOULSourceDataDescrDef	; DESCRIPTOR source
	Sound Descriptor			; sound descriptor
	ObjectReference SyncRef		; emitter synchronization reference	
	Int Position				; playback position
	Int Duration				; total duration
	Bool Paused					; source paused
EndStruct

Struct SOULZoneDef				; speaker ZONE
	String ZoneName				; zone name
	SourceDef Source			; selected listening source
	Float VolumeL				; playback volume left hand
	Float VolumeR				; playback volume right hand
EndStruct

Struct SOULPacket
	String Magic
	Int Version
	String System
	Int PacketType
	Var Data
EndStruct

Struct SOULPacketVCType
	Int Command
EndStruct

Struct SOULPacketSinkType
	String Zone
	Int Command
	Var Data
EndStruct

Struct SOULPacketSourceType
	String Name
	Int Command
	Var Data
EndStruct

Struct DataVolumeControl
	Float VolumeL
	Float VolumeR
EndStruct


; L3 protocol overrides
String Function GetIdentifier()
	Return "SOUL"
EndFunction

String Function GetIdentifierDesc()
	Return "SOUTHLINK"
EndFunction

Int Function GetVersionMajor()
	Return IMPL_VERSION_MAJOR
EndFunction

Int Function GetVersionMinor()
	Return IMPL_VERSION_MINOR
EndFunction

; SOUL packet received event
CustomEvent Started
CustomEvent Stopping
CustomEvent SOULReceiveRaw
CustomEvent SOULReceiveVC
CustomEvent SOULReceiveSink

Group SOULProtocolSettings
	Bool Property RequirePower = true Auto Const
	{ If true, attached reference must be powered for SOUL to work }
EndGroup

; true while SOUL protocol is started
Bool Property IsStarted Hidden
	Bool Function Get()
		Return bStarted
	EndFunction
EndProperty

Bool bStarted = false

Event OnInit()
	Int result = Start()
EndEvent

Event OnWorkshopObjectPlaced(ObjectReference refWorkshop)
	Int result = Start()
EndEvent

Event OnWorkshopObjectDestroyed(ObjectReference refWorkshop)
	Stop()
EndEvent

Event NetLink:LinkLayer.Started(NetLink:LinkLayer refLinkLayer, Var[] noneArgs)
	; link layer has started
	If (bStarted)	; SOUL protocol still started?
	
		; register SOUL protocol with LinkLayer
		_FrameTypeRegistration()
	EndIf
EndEvent

Event NetLink:LinkLayer.Stopping(NetLink:LinkLayer refLinkLayer, Var[] noneArgs)
	If (bStarted)
		; unregister SOUL protocol from LinkLayer
		_FrameTypeRegistration(unregisterFrameType = true)	
	EndIf
EndEvent

Int Function Start()
	If (!IsBoundGameObjectAvailable())
		Return ERROR_UNAVAILABLE
	EndIf
	
	If (bStarted)
		; already started
		Return OK_NOERROR
	EndIf	
	
	; start networklayer base
	Int result = Parent.Start()
	If (!CheckSuccessCode(result))
		; failed
		Return result
	EndIf
	
	; register for link layer lifecycle events
	RegisterForCustomEvent(LinkLayer, "Started")
	RegisterForCustomEvent(LinkLayer, "Stopping")
	
	; if linklayer is started, register networklayer frametypes
	If (LinkLayer.IsStarted)
		result = _FrameTypeRegistration()
		If (!CheckSuccessCode(result))
			Debug.Trace(Self + ": ERROR - Protocol Start failed: FTR for FrameType (" + LinkLayer.NETLINK_FRAMETYPE_SOUL + ") failed with code (" + ResolveErrorCode(result) + ").")
			Return result
		EndIf
	EndIf
	
	;Debug.Trace(Self + ": DEBUG - Protocol scriptname is (" + NetworkLayerScriptname + ").")
	
	; log chatter
	Debug.Trace(Self + ": INFO - Protocol started.")
	
	; SOUL protocol started
	bStarted = true
	
	SendCustomEvent("Started", new Var[0])
	
	Return OK_NOERROR
EndFunction

Function Stop()
	If (bStarted)
		; SOUL protocol no longer started
		bStarted = false

		SendCustomEvent("Stopping", new Var[0])

		; unregister this networklayer from linklayer
		If (LinkLayer != none)

			If (LinkLayer.IsStarted)
				_FrameTypeRegistration(unregisterFrameType = true)
			EndIf
		
			; unregister link layer lifecycle events
			UnRegisterForCustomEvent(LinkLayer, "Started")
			UnRegisterForCustomEvent(LinkLayer, "Stopping")
		EndIf
		
		; stop NetworkLayer base class
		Parent.Stop()

		; log chatter
		Debug.Trace(Self + ": INFO - Protocol stopped.")		
	EndIf
EndFunction

 send a SOUL SINK command to a system/zone
Int Function SendCommandSink(ObjectReference refRecipient, String zoneName, Int commandId, Var commandData)
	If (!_IsDevicePowered())
		Debug.Trace(Self + ": WARNING - SendCommandSink() skipped: Device not powered.")
		Return ERROR_SOUL_NOPOWER
	EndIf
	If (!bStarted)
		Debug.Trace(Self + ": ERROR - SendCommandSink() failed: Protocol not started.")
		Return ERROR_SOUL_NOTSTARTED	
	EndIf

	SOULPacketSinkType outPacket = new SOULPacketSinkType
	outPacket.Zone = zoneName
	outPacket.Command = commandId
	outPacket.Data = commandData
	
	Return SendSOULPacket(refRecipient, systemName, outPacket)
EndFunction

Int Function SendSOULPacket(ObjectReference refRecipient, Int packetType, Var packetData)
	SOULPacket outPacket = new SOULPacket
	
	outPacket.Magic = PROTOCOL_MAGIC
	outPacket.Version = PROTOCOL_VERSION
	outPacket.System = _SystemName
	outPacket.PacketType = packetType
	outPacket.Data = packetData	
	
	If (!bStarted)
		Debug.Trace(Self + ": ERROR - SendSOULPacket() failed: Protocol not started.")
		Return ERROR_SOUL_NOTSTARTED
	EndIf
	If (!_IsDevicePowered())
		Debug.Trace(Self + ": WARNING - SendSinkCommand() skipped: Device not powered.")
		Return ERROR_SOUL_NOPOWER		
	EndIf

	Debug.Trace(Self + ": DEBUG - Sending SOUL Packet (" + outPacket + ") for System (" + outPacket.System + ") to Link Layer...")
	Int success = LinkLayer.LinkSend(refRecipient, NETLINK_FRAMETYPE_SOUL, outPacket)
	Return success	
EndFunction

; function to transmit "raw" SOUL packets
Int Function SendSOULPacketRaw(ObjectReference refRecipient, SOULPacket outPacket)
	If (!bStarted)
		Debug.Trace(Self + ": ERROR - SendSOULPacketRaw() failed: SOUL protocol not started.")
		Return ERROR_SOUL_NOTSTARTED
	EndIf
	If (!_IsDevicePowered())
		Return ERROR_SOUL_NOPOWER
	EndIf

	Debug.Trace(Self + ": DEBUG - Sending SOUL Packet (" + outPacket + ") for System (" + outPacket.System + ") to Link Layer...")
	Int success = LinkLayer.LinkSend(refRecipient, NETLINK_FRAMETYPE_SOUL, outPacket)
	Return success	
EndFunction

Function OnLinkReceive(Var[] eventArgs)
	; SUP accelerated version
	NetLink:API:LinkLayerBase srcLinkLayer = eventArgs[0] as NetLink:LinkLayer
	NetLink:API:LinkLayerBase:NetLinkFrame inFrame = eventArgs[1] as NetLink:API:LinkLayerBase:NetLinkFrame

	; RX filters
	If (srcLinkLayer == none)
		; missing or invalid source linklayer: discard frame.
		Return
	EndIf
	If (inFrame == none)
		; missing or non-netlink frame: discard.
		Return
	EndIf
	If (inFrame.FrameType != NETLINK_FRAMETYPE_SOUL)
		; not a SOUL type NetLink Frame: discard.
		Return
	EndIf
	
	; protocol started?
	If (!bStarted)
		;Debug.Trace(Self + ": WARNING - SOUL type Frame discarded: Protocol not started.")
		Return
	EndIf
	
	; device powered?
	If (!_IsDevicePowered())
		;Debug.Trace(Self + ": WARNING - SOUL type Frame discarded: Device not powered.")
		Return
	EndIf

	; SOUL FrameType received, extract SOUL packet payload
	SOULPacket soulPacket = inFrame.Payload as SOULPacket	

	If (soulPacket == none)
		Debug.Trace(Self + ": WARNING - SOUL type Frame discarded: Null Payload.")
		Return
	EndIf
	If (soulPacket.Magic != PROTOCOL_MAGIC)
		Debug.Trace(Self + ": WARNING - SOUL type Frame discarded: Invalid MAGIC (" + soulPacket.Magic + ").")
		Return	
	EndIf

	; SOUL type frame has proper SOUL protocol version?
	If (soulPacket.Version != PROTOCOL_VERSION)								
		Debug.Trace(Self + ": WARNING - SOUL type Frame discarded: SOUL Protocol version (" + soulPacket.VERSION + ") not supported.")
		Return
	EndIf
	
	;Debug.Trace(Self + ": DEBUG - Received SOUL type Frame from Link Layer.")

	If (EnableRxRaw)
		; generate raw rx event
		Var[] outEventArgs = new Var[3]
		outEventArgs[0] = inFrame.Source			; netlink source ref
		outEventArgs[1] = inFrame.Destination		; netlink destination ref
		outEventArgs[2] = soulPacket				; SOUL packet received
		SendCustomEvent("SOULReceiveRaw", outEventArgs)
	EndIf
	
	; decode PacketType
	If ((soulPacket.PacketType == SOUL_PACKETTYPE_VC) & EnableRxVC) 		; # virtual circuit packet
		rxVCCtrl = inFrame.Data as SOULPacketVCType
		If (rxVCCtrl == none)
			Debug.Trace(Self + ": WARNING - SOUL type Frame discarded: Invalid or missing Data segment for PacketType (SOUL_PACKETTYPE_VC).")
			Return
		EndIf
		; TODO: actual implementation
	
	ElseIf ((inFrame.PacketType == SOUL_PACKETTYPE_SINK) & EnableRxSink)	; # sink packet
		rxSinkCtrl = inFrame.Data as SOULPacketSinkType
		If (rxSinkCtrl == none)
			Debug.Trace(Self + ": WARNING - SOUL type Frame discarded: Invalid or missing Data segment for PacketType (SOUL_PACKETTYPE_SINK).")
			Return
		EndIf
		
		Var[] rxSCEventArgs = new Var[6]
		rxSCEventArgs[0] = inFrame.Source
		rxSCEventArgs[1] = inFrame.Destination
		rxSCEventArgs[2] = soulPacket.System
		rxSCEventArgs[3] = rxSinkCtrl.Zone
		rxSCEventArgs[4] = rxSinkCtrl.Command
		rxSCEventArgs[5] = rxSinkCtrl.Data
		SendCustomEvent("SOULReceiveSink", rxSCEventArgs)
	
	ElseIf ((inFrame.PacketType == SOUL_PACKETTYPE_CONTROL) & EnableRxControl)
	
	ElseIf ((inFrame.PacketType == SOUL_PACKETTYPE_SOURCE) & EnableRxSource)
	
	Else
		Debug.Trace(Self + ": WARNING - SOUL type Frame discarded: Unknown PacketType (" + inFrame.PacketType + ").")
	EndIf
EndFunction


String Function ResolveErrorCode(Int code)				; resolve SOUL protocol error codes
	If (code == OK_NOERROR)
		Return "OK_NOERROR"	
	ElseIf (code == ERROR_SOUL_NOPOWER)
		Return "ERROR_SOUL_NOPOWER"
	ElseIf (code == ERROR_SOUL_NOTSTARTED)
		Return "ERROR_SOUL_NOTSTARTED"
	Else
		Return Parent.ResolveErrorCode(code)
	EndIf
EndFunction

; internal functions
Bool Function _IsDevicePowered()
	If (!RequirePower)
		Return True
	Else
		Return IsPowered()
	EndIf
EndFunction

Int Function _FrameTypeRegistration(Bool unregisterFrameType = false)
	If (!LinkLayer)
		Return ERROR_SOUL_LINKLAYER
	EndIf
	Int nlCode = OK_NOERROR
	If (unregisterFrameType == true)	; unregister frame type
		LinkLayer.FTRUnregisterNetworkLayerForFrameType(Self, LinkLayer.NETLINK_FRAMETYPE_SOUL)
	Else
		nlCode = LinkLayer.FTRRegisterNetworkLayerForFrameType(Self, LinkLayer.NETLINK_FRAMETYPE_SOUL)
	EndIf
	Return nlCode
EndFunction

 

Unfinished. Didn't even try to compile.

I apologize for the delay. I was very busy. Only now was I finally able to calmly sit down at the computer. I remade the model, now I'm redoing the uv.

How do we make touch buttons? Is each button a separate nif (2 sequences)? Are buttons a group with a set of sequences?

FM1_V2_1.jpg

FM1_V2_2.jpg

FM1_V2_3.jpg

FM1_V2_4.jpg

FM1_V2_5.jpg

Edited by South8028
  • Like 1
Link to comment
Share on other sites

Quote

How do we make touch buttons? Is each button a separate nif (2 sequences)? 

Yes, every button must be separate - If they were grouped together, player could only activate the entire group as a whole.

Basically, anything that needs to be interacted with must be a separate object.

Link to comment
Share on other sites

Posted (edited)
9 minutes ago, niston said:

Yes, every button must be separate - If they were grouped together, player could only activate the entire group as a whole.

Basically, anything that needs to be interacted with must be a separate object.

Respectively. Round buttons: Power – 4 states. Config - 4 states. Sensors - 2 states each. I probably need to make small indicators above the buttons. I wanted the splines themselves to glow, but it won't look nice. The buttons themselves are splines with text/numbers (we will attach collisions to them). Collisions are large rectangles hung in a row away from the buttons.

You can make a fun effect with virtual buttons. I'm not sure if this is a good idea, but technically it's not difficult. When you press one button, a series of huge buttons will appear in space - clones of the sensor row in the form of, for example, a hologram with collisions. 🙂

Edited by South8028
Link to comment
Share on other sites

  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...