ResponseEntity returns String instead of xml type in spring boot - spring

I had used spring and weblogic,
I have a method like this:
#RequestMapping(value = "/all/{parentId}", method = RequestMethod.GET)
#ResponseBody
public ResponseEntity<String> getAll(#PathVariable int parentId) {
StringBuffer returnValue = new StringBuffer("");
Power power = iPowerService.loadByEntityId(parentId);
makeTree(power, returnValue);
HttpHeaders responseHeaders = new HttpHeaders();
responseHeaders.add("Content-Type", "text/html; charset=UTF-8");
return new ResponseEntity<String>(returnValue.toString(), responseHeaders, HttpStatus.CREATED);
}
Above method makes xml format for a tree and send it as response to client like this:
<201 Created,
<item text="primary" id="740167402" im0="Mehvar_V.png"
im1="Mehvar_V.png" im2="Mehvar_V.png" isVirtual="true">
<item text="..." im0="leaf.gif" id="t740167402" />
</item>
<item
text="fff"
id="740168675" im0="Mehvar_V.png" im1="Mehvar_V.png" im2="Mehvar_V.png"
isVirtual="true">
<item text="..." im0="leaf.gif" id="t740168675" />
</item>
<item text="mmmehdi" id="12" im0="Mehvar_V.png" im1="Mehvar_V.png"
im2="Mehvar_V.png" isVirtual="true">
<item text="..." im0="leaf.gif" id="t12" />
</item>
<item text="province" id="123" im0="Mehvar_V.png" im1="Mehvar_V.png"
im2="Mehvar_V.png" isVirtual="true">
<item text="..." im0="leaf.gif" id="t123" />
</item>
<item text="power" id="1234" im0="Mehvar_V.png" im1="Mehvar_V.png"
im2="Mehvar_V.png" isVirtual="true">
<item text="..." im0="leaf.gif" id="t1234" />
</item>
,{Content-Type=[text/html; charset=UTF-8]}>
and client converts this response to tree and shows it.
It had worked successfully
When I migrate to spring boot the response of this method is converted to string like this:
"<item text="primary" id="740167402" im0="Mehvar_V.png"
im1="Mehvar_V.png" im2="Mehvar_V.png" isVirtual="true">
<item text="..." im0="leaf.gif" id="t740167402" />
</item>
<item
text="fff"
id="740168675" im0="Mehvar_V.png" im1="Mehvar_V.png" im2="Mehvar_V.png"
isVirtual="true">
<item text="..." im0="leaf.gif" id="t740168675" />
</item>
<item text="mmmehdi" id="12" im0="Mehvar_V.png" im1="Mehvar_V.png"
im2="Mehvar_V.png" isVirtual="true">
<item text="..." im0="leaf.gif" id="t12" />
</item>
<item text="province" id="123" im0="Mehvar_V.png" im1="Mehvar_V.png"
im2="Mehvar_V.png" isVirtual="true">
<item text="..." im0="leaf.gif" id="t123" />
</item>
<item text="power" id="1234" im0="Mehvar_V.png" im1="Mehvar_V.png"
im2="Mehvar_V.png" isVirtual="true">
<item text="..." im0="leaf.gif" id="t1234" />
</item>"
As you see "" SURROUND my output
What and why is happen?
Why my response send string to client.
I want output as same as it worked successfully

With the #ResponseBody, you don't have to wrap your response in a new ResponseEntity, you could juste do this:
#RequestMapping(value = "/all/{parentId}", method = RequestMethod.GET)
#ResponseBody
#ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
public String getAll(#PathVariable int parentId) {
StringBuffer returnValue = new StringBuffer("");
...
return returnValue.toString()
}
or you could juste remove the response body:
#RequestMapping(value = "/all/{parentId}", method = RequestMethod.GET)
public ResponseEntity<String> getAll(#PathVariable int parentId) {

Related

Attaching values ​in a Magento2 XML type input

I tried to add a value in my UI form which is in xml type but I didn't succeed with the methods I found.
For example: this is my code
<field name="client_id">
<argument name="data" xsi:type="array">
<item name="config" xsi:type="array">
<item name="dataType" xsi:type="string">text</item>
<item name="label" xsi:type="string" translate="true">ClientId</item>
<item name="value" xsi:type="string" translate="true">Module\Core\DataObjects</item>
<item name="formElement" xsi:type="string">input</item>
<item name="source" xsi:type="string">smartbusiness</item>
<item name="dataScope" xsi:type="string">client_id</item>
<item name="validation" xsi:type="array">
<item name="required-entry" xsi:type="boolean">true</item>
<item name="min_text_length" xsi:type="number">10</item>
<item name="max_text_length" xsi:type="number">250</item>
<item name="no-whitespace" xsi:type="boolean">true</item>
</item>
</item>
</argument>
</field>
And in my custom class I have that
<?php
namespace Module\Core\DataObjects;
use Module\Core\Model\SettingsFactory;
use Magento\Framework\App\ObjectManager;
class SettingsData
{
protected array $setting = [];
public function __construct()
{
$objectManager = ObjectManager::getInstance();
$modelFactory = $objectManager->get(SettingsFactory::class);
$collection = $modelFactory->create()->getCollection();
$collection->getSelect()->limit(1);
if ($collection->getSize()) {
$this->setting = $collection->getData()[0];
}
}
public function getData()
{
return $this->getClientId();
}
}
Any ideas how I could try?
I also tried to put class="Name of my class" in value, but it didn't work
I tried the above method + to attach the class name in the class attribute
Step 1:- Create a ui_form in
view/adminhtml/ui_component/sunarc_demo_type_form.xml
<?xml version="1.0" encoding="UTF-8"?>
<form xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../../../../../lib/internal/Magento/Framework/Ui/etc/ui_configuration.xsd">
<!--main part of the grid-->
<argument name="data" xsi:type="array">
<item name="js_config" xsi:type="array">
<!--Define where to find the data sources-->
<item name="provider" xsi:type="string">sunarc_demo_type_form.sunarc_demo_type_form_data_source</item>
<item name="deps" xsi:type="string">sunarc_demo_type_form.sunarc_demo_type_form_data_source</item>
</item>
<item name="label" xsi:type="string" translate="true">Add Dummy Data</item>
<item name="layout" xsi:type="array">
<item name="type" xsi:type="string">tabs</item>
</item>
<!-- <item name="buttons" xsi:type="array">
<item name="back" xsi:type="string">Sunarc\Enquiry\Block\Adminhtml\Type\Edit\BackButton</item>
<item name="reset" xsi:type="string">Sunarc\Enquiry\Block\Adminhtml\Type\Edit\ResetButton</item>
<item name="save" xsi:type="string">Sunarc\Enquiry\Block\Adminhtml\Type\Edit\SaveButton</item> -->
<!-- </item> -->
</argument>
<dataSource name="sunarc_demo_type_form_data_source">
<argument name="dataProvider" xsi:type="configurableObject">
<argument name="class" xsi:type="string">Sunarc\Demo\Model\Ui\DataProvider</argument>
<argument name="name" xsi:type="string">sunarc_demo_type_form_data_source</argument>
<argument name="primaryFieldName" xsi:type="string">entity_id</argument>
<argument name="requestFieldName" xsi:type="string">id</argument>
</argument>
<argument name="data" xsi:type="array">
<item name="js_config" xsi:type="array">
<item name="component" xsi:type="string">Magento_Ui/js/form/provider</item>
<item name="submit_url" xsi:type="url" path="*/*/save"/>
</item>
</argument>
</dataSource>
<fieldset name="demo">
<argument name="data" xsi:type="array">
<item name="config" xsi:type="array">
<item name="label" xsi:type="string" translate="true">Add/Edit Type</item>
</item>
</argument>
<!-- This field represents form id and is hidden -->
<field name="entity_id">
<argument name="data" xsi:type="array">
<item name="config" xsi:type="array">
<item name="visible" xsi:type="boolean">false</item>
<item name="dataType" xsi:type="string">text</item>
<item name="formElement" xsi:type="string">input</item>
<item name="source" xsi:type="string">type</item>
</item>
</argument>
</field>
<field name="demo_data">
<argument name="data" xsi:type="array">
<item name="config" xsi:type="array">
<item name="label" xsi:type="string">Demo Data</item>
<item name="visible" xsi:type="boolean">true</item>
<item name="dataType" xsi:type="string">text</item>
<item name="formElement" xsi:type="string">input</item>
<item name="source" xsi:type="string">type</item>
</item>
</argument>
<settings>
<validation>
<rule name="required-entry" xsi:type="boolean">true</rule>
</validation>
</settings>
</field>
<!-- IF YOU WANT TO SHOW STATIC VALUE -->
<field name="text_example" formElement="input">
<argument name="data" xsi:type="array">
<item name="config" xsi:type="array">
<item name="default" xsi:type="string">SAMPLE TEXT HERE</item>
</item>
</argument>
<settings>
<label translate="true">SAMPLE TEXT</label>
<visible>true</visible>
<disabled>false</disabled>
<elementTmpl>ui/form/element/text</elementTmpl>
</settings>
</field>
</fieldset>
</form>
Step 2:- Create a DataSource File in Model/Ui/DataProvider.php
<?php
namespace Sunarc\Demo\Model\Ui;
use Sunarc\Demo\Model\ResourceModel\Demo\CollectionFactory;
class DataProvider extends \Magento\Ui\DataProvider\AbstractDataProvider
{
protected $loadedData;
/**
* #param string $name
* #param string $primaryFieldName
* #param string $requestFieldName
* #param CollectionFactory $typeCollectionFactory
* #param array $meta
* #param array $data
*/
public function __construct(
$name,
$primaryFieldName,
$requestFieldName,
CollectionFactory $typeCollectionFactory,
array $meta = [],
array $data = []
) {
$this->collection = $typeCollectionFactory->create();
parent::__construct($name, $primaryFieldName, $requestFieldName, $meta, $data);
}
/**
* Get data
*
* #return array
*/
public function getData()
{
if (isset($this->loadedData)) {
return $this->loadedData;
}
$items = $this->collection->getItems();
foreach ($items as $item) {
$this->loadedData[$item->getData('entity_id')]['demo']['demo_data'] = $item->getData('demo_data');
}
return $this->loadedData;
// return [];
}
}
Click Here to check the input

Magento 2 dynamicRows as new tab for admin customer edit, how do you get data loaded?

How can I load the data from customer DataProvider plugin into my ui_component dynamicRows?
I have created a new tab in the admin customer edit form, and added my ui_component, which seems to work well. But I can't populate the data already stored in my database.
I have tried to add xml for DataSource, but I think that has conflict with original customer_form.xml DataSource "customer_form.customer_form_data_source" because when I add DataSource, the page no longer loads.
dataSource XML:
<dataSource name="mycustomrows">
<argument name="dataProvider" xsi:type="configurableObject">
<argument name="class" xsi:type="string">MyVendor\MyModule\Model\Customer\DataProvider</argument>
<argument name="primaryFieldName" xsi:type="string">id</argument>
<argument name="requestFieldName" xsi:type="string">id</argument>
<argument name="meta" xsi:type="array">
<item name="myshipping" xsi:type="array">
<item name="config" xsi:type="array">
<item name="label" xsi:type="string" translate="true">My Custom Rows</item>
</item>
</item>
</argument>
<argument name="data" xsi:type="array">
<item name="js_config" xsi:type="array">
<item name="component" xsi:type="string">Magento_Ui/js/grid/provider</item>
</item>
</argument>
</argument>
<argument name="data" xsi:type="array">
<item name="js_config" xsi:type="array">
<item name="component" xsi:type="string">Magento_Ui/js/form/provider</item>
</item>
</argument>
</dataSource>
dataProvider for dataSource:
<?php
namespace MyVendor\MyModule\Model\Customer;
class DataProvider extends \Magento\Ui\DataProvider\AbstractDataProvider
{
protected $loadedData;
protected $collectionFactory;
public function __construct(
$name,
$primaryFieldName,
$requestFieldName,
\MyVendor\MyModule\Model\ResourceModel\Row\Collection $collection,
\MyVendor\MyModule\Model\ResourceModel\Row\CollectionFactory $collectionFactory,
array $meta = [],
array $data = []
) {
$this->collection = $collection;
$this->collectionFactory = $collectionFactory;
parent::__construct($name, $primaryFieldName, $requestFieldName, $meta, $data);
}
public function getData()
{
if (isset($this->loadedData)) {
return $this->loadedData;
}
$collection = $this->collectionFactory->create();
// add Filter for Customer ID
//->setOrder('position', 'ASC');
$items = $collection->getItems();
foreach ($items as $item) {
$this->loadedData[$item->getId()] = $item->getData();
}
return $this->loadedData;
}
}
I believe the data has to be loaded with Plugin for "Magento\Customer\Model\Customer\DataProvider" as I am doing below, but I can't seem to get populate rows on load.
view/adminhtml/ui_component/customer_form.xml
<?xml version="1.0" encoding="UTF-8"?>
<form xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:module:Magento_Ui:etc/ui_configuration.xsd">
<fieldset name="mycustomrows">
<argument name="data" xsi:type="array">
<item name="config" xsi:type="array">
<item name="label" xsi:type="string" translate="true">My Custom Rows</item>
<item name="sortOrder" xsi:type="number">10</item>
</item>
</argument>
<dynamicRows name="mycustomrows">
<settings>
<addButtonLabel translate="true">Add Row</addButtonLabel>
<additionalClasses>
<class name="admin__field-wide">true</class>
</additionalClasses>
<componentType>dynamicRows</componentType>
</settings>
<container name="record" component="Magento_Ui/js/dynamic-rows/record">
<argument name="data" xsi:type="array">
<item name="config" xsi:type="array">
<item name="isTemplate" xsi:type="boolean">true</item>
<item name="is_collection" xsi:type="boolean">true</item>
<item name="componentType" xsi:type="string">container</item>
<item name="positionProvider" xsi:type="string">position</item>
</item>
</argument>
<field name="mycustomrows_select1" formElement="select" sortOrder="10">
<settings>
<dataType>text</dataType>
<label translate="true">Select Field 1</label>
<disabled>false</disabled>
<dataScope>mycustomrows_select1</dataScope>
</settings>
<formElements>
<select>
<settings>
<options class="MyVendor\MyModule\Model\Source\SelectFieldOne"/>
</settings>
</select>
</formElements>
</field>
<field name="mycustomrows_input1" sortOrder="20" formElement="input">
<argument name="data" xsi:type="array">
<item name="config" xsi:type="array">
<item name="source" xsi:type="string">customer</item>
</item>
</argument>
<settings>
<label translate="true">Text Field 1</label>
<dataType>text</dataType>
<dataScope>mycustomrows_text1</dataScope>
</settings>
</field>
<actionDelete sortOrder="30">
<argument name="data" xsi:type="array">
<item name="config" xsi:type="array">
<item name="componentType" xsi:type="string">actionDelete</item>
<item name="dataType" xsi:type="string">text</item>
<item name="fit" xsi:type="boolean">false</item>
<item name="label" xsi:type="string">Actions</item>
<item name="sortOrder" xsi:type="string">500</item>
<item name="additionalClasses" xsi:type="string">data-grid-actions-cell</item>
<item name="template" xsi:type="string">Magento_Backend/dynamic-rows/cells/action-delete</item>
</item>
</argument>
</actionDelete>
</container>
</dynamicRows>
</fieldset>
</form>
etc/adminhtml/di.xml
<?xml version="1.0"?>
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:ObjectManager/etc/config.xsd">
<type name="Magento\Customer\Model\Customer\DataProvider">
<plugin name="customer_get_mycustomrows" type="MyVendor\MyModule\Model\Customer\DataProvider" sortOrder="5" />
</type>
</config>
Model/Customer/DataProvider.php
<?php
namespace MyVendor\MyModule\Model\Customer;
class DataProvider
{
protected $collection;
protected $collectionFactory;
protected $loadedData;
public function __construct(
\MyVendor\MyModule\Model\ResourceModel\Row\Collection $collection,
\MyVendor\MyModule\Model\ResourceModel\Row\CollectionFactory $collectionFactory,
array $data = []
) {
$this->collection = $collection;
$this->collectionFactory = $collectionFactory;
}
public function afterGetData(\Magento\Customer\Model\Customer\DataProvider $subject, $result)
{
if($result){
$customer_id = key($result);
$customerData = $result[$customer_id]['customer'];
if(is_null($this->loadedData)) {
$this->loadedData = array();
$collection = $this->collectionFactory->create(); //->setOrder('position', 'ASC');
$items = $collection->getItems();
foreach ($items as $item) {
$this->loadedData[] = $item->getData();
}
}
$result[$customer_id]['customer']["mycustomrows"] = $this->loadedData;
}
return $result;
}
}
I can't seem to get any records populated when I load a customer edit page.

How to render HTML tags in admin product grid, Magento2.3?

I'm trying to make an anchor link in the product grid view.
I have tried this using UI component, below are the detailed view
xml code:
<column name="column_name" class="Vendor\Module\Ui\Component\Listing\Column\link">
<argument name="data" xsi:type="array">
<item name="config" xsi:type="array">
<item name="bodyTmpl" xsi:type="string">ui/grid/cells/html</item>
<item name="filter" xsi:type="string">text</item>
<item name="label" xsi:type="string" translate="true">Label</item>
<item name="sortOrder" xsi:type="number">50</item>
</item>
</argument>
</column>
datasource code:
$html = ''. __('Label').'';
$item[$this->getData('name')] = $html;
Getting html like this: Label
I want 'Label' with the anchor link.

Magento2 extension: add link to product grid

I'm developing extension for magento 2.1.3 ce. I want to add a link to each product in the products grid in admin-panel:
I want to have a link in this column, how to change my extension to have a link instead of plain text?
My Magento extension code (app\code\MyCompany\ExampleAdminNewPage\view\adminhtml\ui_component\product_listing.xml):
<?xml version="1.0"?>
<listing xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:module:Magento_Ui:etc/ui_configuration.xsd">
<columns name="product_columns" class="Magento\Catalog\Ui\Component\Listing\Columns">
<column name="sku">
<argument name="data" xsi:type="array">
<item name="config" xsi:type="array">
<item name="filter" xsi:type="string">text</item>
<item name="add_field" xsi:type="boolean">true</item>
<item name="label" xsi:type="string" translate="true">Custom Field2</item>
<item name="sortOrder" xsi:type="number">75</item>
</item>
</argument>
</column>
</columns>
</listing>
in pseudo code what i want is:
<column name="{http://mysite/}"+"sku">
If the URL is internal, try this:
Step 1: config the column like this:
<column name="custom_field2" class="MyCompany\ExampleAdminNewPage\Ui\Component\Listing\Column\HTMLLink">
<argument name="data" xsi:type="array">
<item name="config" xsi:type="array">
<!-- other configurations -->
<item name="bodyTmpl" xsi:type="string">ui/grid/cells/html</item>
</item>
</argument>
</column>
Step 2: create file <Magento_ROOT>/app/code/MyCompany\ExampleAdminNewPage/Ui/Component/Listing/Column/HtmlLink.php
use Magento\Framework\Escaper;
use Magento\Ui\Component\Listing\Columns\Column;
use Magento\Framework\View\Element\UiComponent\ContextInterface;
use Magento\Framework\View\Element\UiComponentFactory;
class HTMLLink extends Column{
protected $escaper;
public function __construct(
ContextInterface $context,
UiComponentFactory $uiComponentFactory,
Escaper $escaper,
array $components = [],
array $data = []
) {
$this->escaper = $escaper;
parent::__construct($context, $uiComponentFactory, $components, $data);
}
public function prepareDataSource(array $dataSource){
if (isset($dataSource['data']['items'])) {
$fieldName = $this->getData('name');
foreach ($dataSource['data']['items'] as & $item) {
$html = 'product';
$item[$fieldName] = $this->escaper->escapeHtml($html, ['a']);
}
}
return $dataSource;
}
}

Building in-game editor, need assistance with Load and Save

I've been working on a game project with a small group for a bit now and we've hit a block. One of the features of this game is the ability for users to generate their own levels through the use of an in-game editor. The editor creates a Level object which stores the length and width of the level and a two-dimensional array of Tile objects. We've successfully implemented the camera system and can edit together a simple concept level without too much difficulty, but the process of successfully saving the level and loading it back up later is a concept that's proving difficult, and I was hoping one of you could offer some guidance to get the intended functionality down.
In its current state, when the user presses the 'S' key, our LevelManager class runs the SaveLevel method below:
public static void SaveLevel()
{
XmlWriterSettings settings = new XmlWriterSettings();
settings.Indent = true;
using (XmlWriter writer = XmlWriter.Create("example.xml", settings))
{
IntermediateSerializer.Serialize(writer, CurrentLevel, null);
}
}
Which serializes our level (CurrentLevel) into an XML file in the project (We'll worry about saving to different files after we get this basic setup working.) I ran the program, created a small map and saved it, and here's the output in the resulting XML file:
<?xml version="1.0" encoding="utf-8"?>
<XnaContent>
<Asset Type="LevelEditorPrototype.Level">
<TileGrid>
<Item>
<Item Type="LevelEditorPrototype.TileFloor">
<X>0</X>
<Y>0</Y>
<Width>32</Width>
<Height>32</Height>
<Origin>0 0</Origin>
<Depth>0</Depth>
<Tint>FFFFFFFF</Tint>
</Item>
<Item Type="LevelEditorPrototype.TileBlock">
<X>0</X>
<Y>32</Y>
<Width>32</Width>
<Height>32</Height>
<Origin>0 0</Origin>
<Depth>0</Depth>
<Tint>FF0000FF</Tint>
</Item>
<Item Type="LevelEditorPrototype.TileVoid">
<X>0</X>
<Y>64</Y>
<Width>32</Width>
<Height>32</Height>
<Origin>0 0</Origin>
<Depth>0</Depth>
<Tint>FFFF0000</Tint>
</Item>
<Item Type="LevelEditorPrototype.TileFloor">
<X>0</X>
<Y>96</Y>
<Width>32</Width>
<Height>32</Height>
<Origin>0 0</Origin>
<Depth>0</Depth>
<Tint>FFFFFFFF</Tint>
</Item>
</Item>
<Item>
<Item Type="LevelEditorPrototype.TileVoid">
<X>32</X>
<Y>0</Y>
<Width>32</Width>
<Height>32</Height>
<Origin>0 0</Origin>
<Depth>0</Depth>
<Tint>FFFF0000</Tint>
</Item>
<Item Type="LevelEditorPrototype.TileFloor">
<X>32</X>
<Y>32</Y>
<Width>32</Width>
<Height>32</Height>
<Origin>0 0</Origin>
<Depth>0</Depth>
<Tint>FFFFFFFF</Tint>
</Item>
<Item Type="LevelEditorPrototype.TileBlock">
<X>32</X>
<Y>64</Y>
<Width>32</Width>
<Height>32</Height>
<Origin>0 0</Origin>
<Depth>0</Depth>
<Tint>FF0000FF</Tint>
</Item>
<Item Type="LevelEditorPrototype.TileVoid">
<X>32</X>
<Y>96</Y>
<Width>32</Width>
<Height>32</Height>
<Origin>0 0</Origin>
<Depth>0</Depth>
<Tint>FFFF0000</Tint>
</Item>
</Item>
<Item>
<Item Type="LevelEditorPrototype.TileBlock">
<X>64</X>
<Y>0</Y>
<Width>32</Width>
<Height>32</Height>
<Origin>0 0</Origin>
<Depth>0</Depth>
<Tint>FF0000FF</Tint>
</Item>
<Item Type="LevelEditorPrototype.TileVoid">
<X>64</X>
<Y>32</Y>
<Width>32</Width>
<Height>32</Height>
<Origin>0 0</Origin>
<Depth>0</Depth>
<Tint>FFFF0000</Tint>
</Item>
<Item Type="LevelEditorPrototype.TileFloor">
<X>64</X>
<Y>64</Y>
<Width>32</Width>
<Height>32</Height>
<Origin>0 0</Origin>
<Depth>0</Depth>
<Tint>FFFFFFFF</Tint>
</Item>
<Item Type="LevelEditorPrototype.TileBlock">
<X>64</X>
<Y>96</Y>
<Width>32</Width>
<Height>32</Height>
<Origin>0 0</Origin>
<Depth>0</Depth>
<Tint>FF0000FF</Tint>
</Item>
</Item>
<Item>
<Item Type="LevelEditorPrototype.TileFloor">
<X>96</X>
<Y>0</Y>
<Width>32</Width>
<Height>32</Height>
<Origin>0 0</Origin>
<Depth>0</Depth>
<Tint>FFFFFFFF</Tint>
</Item>
<Item Type="LevelEditorPrototype.TileBlock">
<X>96</X>
<Y>32</Y>
<Width>32</Width>
<Height>32</Height>
<Origin>0 0</Origin>
<Depth>0</Depth>
<Tint>FF0000FF</Tint>
</Item>
<Item Type="LevelEditorPrototype.TileVoid">
<X>96</X>
<Y>64</Y>
<Width>32</Width>
<Height>32</Height>
<Origin>0 0</Origin>
<Depth>0</Depth>
<Tint>FFFF0000</Tint>
</Item>
<Item Type="LevelEditorPrototype.TileFloor">
<X>96</X>
<Y>96</Y>
<Width>32</Width>
<Height>32</Height>
<Origin>0 0</Origin>
<Depth>0</Depth>
<Tint>FFFFFFFF</Tint>
</Item>
</Item>
</TileGrid>
</Asset>
</XnaContent>
So at the very least we do have data information on the tiles generated in the level, so that's something. We'd like our users to be able to load up saved levels during runtime as well, so we mapped the 'L' key to load that saved XML file, and that's where the problem shows up. Our read looks like this:
public static void LoadLevel()
{
using (FileStream stream = new FileStream("example.xml", FileMode.Open))
{
using (XmlReader reader = XmlReader.Create(stream))
{
currentLevel = IntermediateSerializer.Deserialize<Level>(reader, null);
}
}
}
When we try testing that functionality, we get this error:
System.MethodAccessException was unhandled
HResult=-2146233072
Message=Attempt by method 'DynamicClass.ReflectionEmitUtils(System.Object, System.Object)' to access method 'DynamicClass.ReflectionEmitUtils(System.Object, System.Object)' failed.
I have a sneaking suspicion that the IntermediateSerializer doesn't quite work how we want it to work, but I'm not sure how else to parse and store the data effectively. Is there a different setup I should be using here?
The most effective way to be 100% sure of saving and loading tile-based levels have, in my experience, to use BinaryWriter and BinaryReader.
Our level-structure has been a lot different from yours, though; We have many layers. Each layer uses a tileset and consists of instances of Tile. Tile holds its position (Vector2D) and a TileId (index of the tile in the tileset-texture).
The way we put objects in levels are with tilesets that are replaced by real objects on loading.
Anyways, a suitably generic way to save and load data is by letting your classes have a contructor that can take a BinaryReader as an argument, and a method to write itself to a BinaryWriter.
like this:
public Tile(BinaryReader reader)
{
Position.X = reader.ReadFloat();
Position.Y = reader.ReadFloat();
TileId = reader.ReadInt32();
}
public void WriteToStream(BinaryWriter writer)
{
writer.Write(Position.X);
writer.Write(Position.Y);
writer.Write(TileId);
}
if you only have one class to load, you can then simply:
for loading:
var tiles = new List<Tile>();
var reader = new BinaryReader(File.Open("level.bin"));
while (reader.BaseStream.Position < reader.BaseStream.Length)
{
var tile = new Tile(reader);
tiles.Add(tile);
}
reader.Close();
For saving:
var tiles; //lets pretend this is the level
var writer = new BinaryWriter(File.Create("level.bin"));
foreach (var tile in tiles)
{
tile.WriteToStream(writer);
}
writer.Flush(); //IMPORTANT!!!
writer.Close();
If, however, your list contains items of different types, you need to store the type also.
A pretty generic way to do this is by inserting:
writer.Write(tile.GetType().FullName);
before tile.WriteToStream(writer);
and then on loading you need to:
var tileType = Type.GetType(reader.ReadString()); //Read the type from the stream
var constructor = tileType.GetConstructor(new [] { typeof(BinaryReader)}); //get a constructor that can use a binaryreader
var tile = constructor.Invoke(new [] { reader }); //use said constructor to create an instance
Hope this helps. And note that I am writing this out of memory, so syntax errors are probable....

Resources