Class: Factorix::SerDes::Serializer
- Inherits:
-
Object
- Object
- Factorix::SerDes::Serializer
- Defined in:
- lib/factorix/ser_des/serializer.rb
Overview
Serialize data to binary format
This class provides methods to serialize various data types to Factorio’s binary file format, following the specifications documented in the Factorio wiki.
Instance Method Summary collapse
-
#initialize(stream, logger: nil) ⇒ Serializer
constructor
Create a new Serializer instance.
-
#write_bool(bool) ⇒ void
Write a boolean value.
-
#write_bytes(data) ⇒ void
Write raw bytes to the stream.
-
#write_dictionary(dict) ⇒ void
Write a dictionary.
-
#write_double(dbl) ⇒ void
Write a double-precision floating point number.
-
#write_game_version(game_version) ⇒ void
Write a GameVersion object.
-
#write_list(list) ⇒ void
Write a list.
-
#write_long(long) ⇒ void
Write a signed long integer (8 bytes).
-
#write_mod_version(mod_version) ⇒ void
Write a MODVersion object.
-
#write_optim_u16(uint16) ⇒ void
Write a space-optimized 16-bit unsigned integer.
-
#write_optim_u32(uint32) ⇒ void
Write a space-optimized 32-bit unsigned integer.
-
#write_property_tree(obj) ⇒ void
Write a property tree.
-
#write_str(str) ⇒ void
Write a string.
-
#write_str_property(str) ⇒ void
Write a string property.
-
#write_u16(uint16) ⇒ void
Write an unsigned 16-bit integer.
-
#write_u32(uint32) ⇒ void
Write an unsigned 32-bit integer.
-
#write_u8(uint8) ⇒ void
Write an unsigned 8-bit integer.
-
#write_unsigned_long(ulong) ⇒ void
Write an unsigned long integer (8 bytes).
Constructor Details
#initialize(stream, logger: nil) ⇒ Serializer
Create a new Serializer instance
20 21 22 23 24 25 26 |
# File 'lib/factorix/ser_des/serializer.rb', line 20 def initialize(stream, logger: nil) super(logger:) raise ArgumentError, "can't write to the given argument" unless stream.respond_to?(:write) @stream = stream logger.debug "Initializing Serializer" end |
Instance Method Details
#write_bool(bool) ⇒ void
This method returns an undefined value.
Write a boolean value
90 |
# File 'lib/factorix/ser_des/serializer.rb', line 90 def write_bool(bool) = write_u8(bool ? 0x01 : 0x00) |
#write_bytes(data) ⇒ void
This method returns an undefined value.
Write raw bytes to the stream
33 34 35 36 37 38 |
# File 'lib/factorix/ser_des/serializer.rb', line 33 def write_bytes(data) raise ArgumentError if data.nil? return if data.empty? @stream.write(data) end |
#write_dictionary(dict) ⇒ void
This method returns an undefined value.
Write a dictionary
156 157 158 159 160 161 162 163 |
# File 'lib/factorix/ser_des/serializer.rb', line 156 def write_dictionary(dict) logger.debug("Writing dictionary", size: dict.size) write_u32(dict.size) dict.each do |(key, value)| write_str_property(key) write_property_tree(value) end end |
#write_double(dbl) ⇒ void
This method returns an undefined value.
Write a double-precision floating point number
126 |
# File 'lib/factorix/ser_des/serializer.rb', line 126 def write_double(dbl) = write_bytes([dbl].pack("d")) |
#write_game_version(game_version) ⇒ void
This method returns an undefined value.
Write a GameVersion object
132 |
# File 'lib/factorix/ser_des/serializer.rb', line 132 def write_game_version(game_version) = game_version.to_a.each {|u16| write_u16(u16) } |
#write_list(list) ⇒ void
This method returns an undefined value.
Write a list
145 146 147 148 149 |
# File 'lib/factorix/ser_des/serializer.rb', line 145 def write_list(list) logger.debug("Writing list", size: list.size) write_optim_u32(list.size) list.each {|e| write_property_tree(e) } end |
#write_long(long) ⇒ void
This method returns an undefined value.
Write a signed long integer (8 bytes)
169 |
# File 'lib/factorix/ser_des/serializer.rb', line 169 def write_long(long) = write_bytes([long].pack("q<")) |
#write_mod_version(mod_version) ⇒ void
This method returns an undefined value.
Write a MODVersion object
138 |
# File 'lib/factorix/ser_des/serializer.rb', line 138 def write_mod_version(mod_version) = mod_version.to_a.each {|u16| write_optim_u16(u16) } |
#write_optim_u16(uint16) ⇒ void
This method returns an undefined value.
Write a space-optimized 16-bit unsigned integer
63 64 65 66 67 68 69 70 |
# File 'lib/factorix/ser_des/serializer.rb', line 63 def write_optim_u16(uint16) if uint16 < 0xFF write_u8(uint16 & 0xFF) else write_u8(0xFF) write_u16(uint16) end end |
#write_optim_u32(uint32) ⇒ void
This method returns an undefined value.
Write a space-optimized 32-bit unsigned integer
77 78 79 80 81 82 83 84 |
# File 'lib/factorix/ser_des/serializer.rb', line 77 def write_optim_u32(uint32) if uint32 < 0xFF write_u8(uint32 & 0xFF) else write_u8(0xFF) write_u32(uint32) end end |
#write_property_tree(obj) ⇒ void
This method returns an undefined value.
Write a property tree
182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 |
# File 'lib/factorix/ser_des/serializer.rb', line 182 def write_property_tree(obj) logger.debug("Writing property tree", type: obj.class.name) case obj when nil # Type 0 - None (null value) write_u8(0) write_bool(false) when true, false # Type 1 - Boolean write_u8(1) write_bool(false) write_bool(obj) when Float # Type 2 - Number (double) write_u8(2) write_bool(false) write_double(obj) when String # Type 3 - String write_u8(3) write_bool(false) write_str_property(obj) when Array # Type 4 - List write_u8(4) write_bool(false) write_list(obj) when Hash # Type 5 - Dictionary write_u8(5) write_bool(false) write_dictionary(obj) when SignedInteger # Type 6 - Signed integer write_u8(6) write_bool(false) write_long(obj.__getobj__) when UnsignedInteger # Type 7 - Unsigned integer write_u8(7) write_bool(false) write_unsigned_long(obj.__getobj__) else logger.debug("Unknown property type", type: obj.class.name) raise UnknownPropertyType, "Unknown property type: #{obj.class}" end end |
#write_str(str) ⇒ void
This method returns an undefined value.
Write a string
97 98 99 100 101 102 103 104 105 |
# File 'lib/factorix/ser_des/serializer.rb', line 97 def write_str(str) if str.encoding != Encoding::UTF_8 && !(str.encoding == Encoding::ASCII_8BIT && str.force_encoding(Encoding::UTF_8).valid_encoding?) logger.debug("String encoding error", expected: "UTF-8", got: str.encoding.name) raise ArgumentError, "String must be UTF-8 encoded, got #{str.encoding}" end write_optim_u32(str.bytesize) write_bytes(str.b) end |
#write_str_property(str) ⇒ void
This method returns an undefined value.
Write a string property
112 113 114 115 116 117 118 119 |
# File 'lib/factorix/ser_des/serializer.rb', line 112 def write_str_property(str) if str.empty? write_bool(true) else write_bool(false) write_str(str) end end |
#write_u16(uint16) ⇒ void
This method returns an undefined value.
Write an unsigned 16-bit integer
50 |
# File 'lib/factorix/ser_des/serializer.rb', line 50 def write_u16(uint16) = write_bytes([uint16].pack("v")) |
#write_u32(uint32) ⇒ void
This method returns an undefined value.
Write an unsigned 32-bit integer
56 |
# File 'lib/factorix/ser_des/serializer.rb', line 56 def write_u32(uint32) = write_bytes([uint32].pack("V")) |
#write_u8(uint8) ⇒ void
This method returns an undefined value.
Write an unsigned 8-bit integer
44 |
# File 'lib/factorix/ser_des/serializer.rb', line 44 def write_u8(uint8) = write_bytes([uint8].pack("C")) |
#write_unsigned_long(ulong) ⇒ void
This method returns an undefined value.
Write an unsigned long integer (8 bytes)
175 |
# File 'lib/factorix/ser_des/serializer.rb', line 175 def write_unsigned_long(ulong) = write_bytes([ulong].pack("Q<")) |